Introducing Access Control - Java

As you know, encapsulation links data with the code that manipulates it. However, encapsulation provides another important attribute: access control.

Introducing
Access Control

As you know, encapsulation
links data with the code that manipulates it. However, encapsulation provides
another important attribute: access
control. Through encapsulation, you can control what parts of a program can
access the members of a class. By controlling access, you can prevent misuse.
For example, allowing access to data only through a well-defined set of
methods, you can prevent the misuse of that data. Thus, when correctly
implemented, a class creates a “black box” which may be used, but the inner workings
of which are not open to tampering. However, the classes that were presented
earlier do not completely meet this goal. For example, consider the Stack class shown at the end of Chapter
6. While it is true that the methods push(
) and pop( ) do provide a
controlled interface to the stack, this interface is not enforced. That is, it
is possible for another part of the program to bypass these methods and access
the stack directly. Of course, in the wrong hands, this could lead to trouble.
In this section, you will be introduced to the mechanism by which you can
precisely control access to the various members of a class.

How a
member can be accessed is determined by the access
modifier attached to its declaration. Java supplies a rich set of access
modifiers. Some aspects of access control are related mostly to inheritance or
packages. (A package is, essentially,
a grouping of classes.) These parts of Java’s access control mechanism will be
discussed later. Here, let’s begin by examining access control as it applies to
a single class. Once you understand the fundamentals of access control, the
rest will be easy.

Java’s access modifiers are public, private, and protected.
Java also defines a default access level. protected
applies only when inheritance is involved. The other access modifiers are
described next.

Let’s
begin by defining public and private. When a member of a class is
modified by public, then that member
can be accessed by any other code. When a member of a class isspecified as private, then that member can only be accessed by other members of
its class. Now you can understand why main(
) has always been preceded by the public
modifier. It is called by code that is outside the program—that is, by the Java
run-time system. When no access modifier is used, then by default the member of
a class is public within its own package, but cannot be accessed outside of its
package. (Packages are discussed in the following chapter.)

In the
classes developed so far, all members of a class have used the default access
mode. However, this is not what you will typically want to be the case.
Usually, you will want to restrict access to the data members of a
class—allowing access only through methods. Also, there will be times when you
will want to define methods that are private to a class.

An
access modifier precedes the rest of a member’s type specification. That is, it
must begin a member’s declaration statement. Here is an example:

public int i; private double
j;

private int myMethod(int a, char b) { //...

To understand the effects of
public and private access, consider the following program:

/*This
program demonstrates the difference between public and private.

*/

class Test {

int a; // default access

public int b; // public access

private int c; // private access

// methods to access c

void setc(int i) { // set c's
value

c = i;

}

int getc() { // get c's value

return c;

}

}

class AccessTest {

public static void
main(String args[]) { Test ob = new Test();

These are OK, a and b may be accessed directly
ob.a = 10;

ob.b = 20;

This is not OK and will cause an error

ob.c = 100; // Error!

You must access c through its methods
ob.setc(100); // OK

System.out.println("a, b, and c: " +
ob.a + " " +

ob.b + " " + ob.getc());

}

}

As you can see, inside the Test class, a uses default access, which for this example is the same as
specifying public. b is explicitly specified as public. Member c is given private access. This means that it cannot be accessed by
code outside of its class. So, inside the AccessTest
class, c cannot be used
directly. It must be accessed through its public methods: setc( ) and getc( ). If
you were to remove the comment symbol from the beginning of thefollowing line,

// ob.c = 100;

// Error!

then you
would not be able to compile this program because of the access violation. To
see how access control can be applied to a more practical example, consider the

following improved version of
the Stack class shown at the end of
Chapter 6.

// This class defines an
integer stack that can hold 10 values.

class Stack {

/*Now,
both stck and tos are private. This means that they cannot be accidentally or
maliciously altered in a way that would be harmful to the stack.

*/

private int stck[] = new
int[10]; private int tos;

Initialize top-of-stack Stack() {

tos = -1;

}

Push an item onto the stack void push(int item)
{

if(tos==9)

System.out.println("Stack
is full."); else

stck[++tos] = item;

}

// Pop an item from the stack
int pop() {

if(tos < 0) {

System.out.println("Stack
underflow."); return 0;

}

else

return stck[tos--];

}

}

As you can see, now both stck, which holds the stack, and tos, which is the index of the top of
the stack, are specified as private.
This means that they cannot be accessed or altered except through push( ) and pop( ). Making tos
private, for example, prevents other parts of your program from inadvertently
setting it to a value that is beyond the end of the stck array.

The
following program demonstrates the improved Stack class. Try removing the commented-out lines to prove to
yourself that the stck and tos members are, indeed, inaccessible.

pop those numbers off the stack
System.out.println("Stack in mystack1:"); for(int i=0; i<10; i++)

System.out.println(mystack1.pop());

System.out.println("Stack in
mystack2:");

for(int i=0; i<10; i++)
System.out.println(mystack2.pop());

these statements are not legal

mystack1.tos = -2;

mystack2.stck[3] = 100;

}

}

Although methods will usually
provide access to the data defined by a class, this does not always have to be the
case. It is perfectly proper to allow an instance variable to be public when
there is good reason to do so. For example, most of the simple classes in this
book were created with little concern about controlling access to instance
variables for the sake of simplicity. However, in most real-world classes, you
will need to allow operations on data only through methods. The next chapter
will return to the topic of access control. As you will see, it is particularly
important when inheritance is involved.