Sunday, July 4, 2010

Access Control

When writing new classes, it’s a good idea to pay attention to the issue of access
control. Recall that making a member of a class public makes it accessible from anywhere, including from other classes. On the other hand, a private member can
only be used in the class where it is defined.
In the opinion of many programmers, almost all member variables should be declared
private. This gives you complete control over what can be done with the
variable. Even if the variable itself is private, you can allow other classes to find out
what its value is by providing a public accessor method that returns the value of
the variable. For example, if your class contains a private member variable, title,
of type String, you can provide a method
public String getTitle() { return title; }
that returns the value of title. By convention, the name of an accessor method for
a variable is obtained by capitalizing the name of variable and adding “get” in front
of the name. So, for the variable title, we get an accessor method named “get” +
“Title”, or getTitle(). Because of this naming convention, accessor methods are
more often referred to as getter methods. A getter method provides “read access” to
a variable.
You might also want to allow “write access” to a private variable. That is, you
might want to make it possible for other classes to specify a new value for the variable.
This is done with a setter method. (If you don’t like simple, Anglo-Saxon
words, you can use the fancier term mutator method.) The name of a setter method
should consist of “set” followed by a capitalized copy of the variable’s name, and it
should have a parameter with the same type as the variable. A setter method for the
variable title could be written
public void setTitle( String newTitle ) { title = newTitle; }
It is actually very common to provide both a getter and a setter method for a
private member variable. Since this allows other classes both to see and to change
the value of the variable, you might wonder why not just make the variable public?
The reason is that getters and setters are not restricted to simply reading and writing
the variable’s value. In fact, they can take any action at all. For example, a getter
method might keep track of the number of times that the variable has been accessed:
public String getTitle() {
titleAccessCount++; / / Increment member v a r i a b l e t i t leAc ces sCount .
return title;
}
and a setter method might check that the value that is being assigned to the variable
is legal:
public void setTitle( String newTitle ) {
if ( newTitle == null ) / / Don ’ t al low n u l l s t r i n g s as t i t l e s !
title = " ( Unt i t led ) "; / / Use an appropr iate d e f a u l t value instead .
else
title = newTitle; }
Even if you can’t think of any extra chores to do in a getter or setter method, you
might change your mind in the future when you redesign and improve your class. If
you’ve used a getter and setter from the beginning, you can make the modification
to your class without affecting any of the classes that use your class. The private
member variable is not part of the public interface of your class; only the public
getter and setter methods are. If you haven’t used get and set from the beginning,
you’ll have to contact everyone who uses your class and tell them, “Sorry guys, you’ll
have to track down every use that you’ve made of this variable and change your code.”

Class Members and Instance Members

A class definition is made of members or components. A class can define variables (or
fields) and methods. Variables and methods can be static or non-static i.e. they are
defined with or without the keyword static.
e.g.
static double lastStudentNumber; / / a s t a t i c member / v a r i a b l e / f i e l d
double studentNumber; / / a non−s t a t i c v a r i a b l e
static void printLastNumber() {...} / / a s t a t i c member /method
void printNumber() {...} / / a non−s t a t i c method
The non-static members of a class (variables and methods) are also known as
instance variables and methods while the non-static members are also known as class
variables and class methods. Each instance of a class (each object) gets its own copy of
all the instance variables defined in the class. When you create an instance of a class,
the system allocates enough memory for the object and all its instance variables.
In addition to instance variables, classes can declare class variables. A class variable
contains information that is shared by all instances (objects) of the class. If one
object changes the variable, it changes for all other objects of that type. e.g. A Student
number generator in a NewStudent class.
You can invoke a class method directly from the class, whereas you must invoke
instance methods on a particular instance. e.g. The methods in the Math class are
static and can be invoked without creating an instance of the Math class for e.g. we
can say Math.sqrt(x).
Consider a simple class whose job is to group together a few static member variables
for example a class could be used to store information about the person who is
using the program:
class UserData { static String name; static int age; }
In programs that use this class, there is one copy each of the variables UserData.name
and UserData.age. There can only be one “user,” since we only have memory space
to store data about one user. The class, UserData, and the variables it contains exist
as long as the program runs. Now, consider a similar class that includes non-static
variables:
class PlayerData { String name; int age; }
In this case, there is no such variable as PlayerData.name or PlayerData.age,
since name and age are not static members of PlayerData. There is nothing much in the class except the potential to create objects. But, it’s a lot of potential, since
it can be used to create any number of objects! Each object will have its own variables
called name and age. There can be many “players” because we can make new
objects to represent new players on demand. A program might use this class to store
information about multiple players in a game. Each player has a name and an age.
When a player joins the game, a new PlayerData object can be created to represent
that player. If a player leaves the game, the PlayerData object that represents that
player can be destroyed. A system of objects in the program is being used to dynamically
model what is happening in the game. You can’t do this with “static” variables!
An object that belongs to a class is said to be an instance of that class and the
variables that the object contains are called instance variables. The methods that
the object contains are called instance methods.
For example, if the PlayerData class, is used to create an object, then that object
is an instance of the PlayerData class, and name and age are instance variables in the
object. It is important to remember that the class of an object determines the types
of the instance variables; however, the actual data is contained inside the individual
objects, not the class. Thus, each object has its own set of data.
The source code for methods are defined in the class yet it’s better to think of the
instance methods as belonging to the object, not to the class. The non-static methods
in the class merely specify the instance methods that every object created from the
class will contain. For example a draw() method in two different objects do the same
thing in the sense that they both draw something. But there is a real difference
between the two methods—the things that they draw can be different. You might
say that the method definition in the class specifies what type of behavior the objects
will have, but the specific behavior can vary from object to object, depending on the
values of their instance variables.
The static and the non-static portions of a class are very different things and serve
very different purposes. Many classes contain only static members, or only non-static.
However, it is possible to mix static and non-static members in a single class. The
“static” definitions in the source code specify the things that are part of the class itself,
whereas the non-static definitions in the source code specify things that will become
part of every instance object that is created from the class. Static member variables
and static member methods in a class are sometimes called class variables and
class methods, since they belong to the class itself, rather than to instances of that
class.
So far, we’ve been talking mostly in generalities. Let’s now look at a specific
example to see how classes and objects work. Consider this extremely simplified
version of a Student class, which could be used to store information about students
taking a course:
public class Student {
public String name; / / Student ’ s name . p u b l i c double test1 ,
test2, test3; / / Grades on three t e s t s .
public double getAverage() { / / compute average t e s t grade r e t u r n
(test1 + test2 + test3) / 3; }
} / / end of class Student
None of the members of this class are declared to be static, so the class exists
only for creating objects. This class definition says that any object that is an instance of the Student class will include instance variables named name, test1, test2, and
test3, and it will include an instance method named getAverage(). The names
and tests in different objects will generally have different values. When called for
a particular student, the method getAverage() will compute an average using that
student’s test grades. Different students can have different averages. (Again, this is
what it means to say that an instance method belongs to an individual object, not to
the class.)
In JAVA, a class is a type, similar to the built-in types such as int and boolean.
So, a class name can be used to specify the type of a variable in a declaration statement,
the type of a formal parameter, or the return type of a method. For example, a
program could define a variable named std of type Student with the statement
Student std;
However, declaring a variable does not create an object! This is an important
point, which is related to this Very Important Fact:
In JAVA, no variable can ever hold an object. A variable can only hold a
reference to an object.
You should think of objects as floating around independently in the computer’s
memory. In fact, there is a special portion of memory called the heap where objects
live. Instead of holding an object itself, a variable holds the information necessary
to find the object in memory. This information is called a reference or pointer to the
object. In effect, a reference to an object is the address of the memory location where
the object is stored. When you use a variable of class type, the computer uses the
reference in the variable to find the actual object.
In a program, objects are created using an operator called new, which creates an
object and returns a reference to that object. For example, assuming that std is a
variable of type Student, declared as above, the assignment statement
std = new Student();
would create a new object which is an instance of the class Student, and it would
store a reference to that object in the variable std. The value of the variable is a
reference to the object, not the object itself. It is not quite true to say that the object
is the “value of the variable std”. It is certainly not at all true to say that the object
is “stored in the variable std.” The proper terminology is that “the variable std refers
to the object,”.
So, suppose that the variable std refers to an object belonging to the class Student.
That object has instance variables name, test1, test2, and test3. These instance
variables can be referred to as std.name, std.test1, std.test2, and std.test3.
This follows the usual naming convention that when B is part of A, then the full name
of B is A.B. For example, a program might include the lines
System.out.println(" Hello , " + std.name + " . Your tes t grades are : ");
System.out.println(std.test1);
System.out.println(std.test2);
System.out.println(std.test3);
This would output the name and test grades from the object to which std refers.
Similarly, std can be used to call the getAverage() instance method in the object by
saying std.getAverage(). To print out the student’s average, you could say:
System.out.println( " Your average i s " + std.getAverage() );
More generally, you could use std.name any place where a variable of type String
is legal. You can use it in expressions. You can assign a value to it. You can pass it
as a parameter to method. You can even use it to call methods from the String class.
For example, std.name.length() is the number of characters in the student’s name.
It is possible for a variable like std, whose type is given by a class, to refer to no
object at all. We say in this case that std holds a null reference. The null reference
is written in JAVA as “null”. You can store a null reference in the variable std by
saying “std = null;” and you could test whether the value of “std” is null by testing
“if (std == null) . . .”.
If the value of a variable is null, then it is, of course, illegal to refer to instance
variables or instance methods through that variable–since there is no object, and
hence no instance variables to refer to. For example, if the value of the variable st is
null, then it would be illegal to refer to std.test1. If your program attempts to use a
null reference illegally like this, the result is an error called a null pointer exception.
Let’s look at a sequence of statements that work with objects:
Student std, std1, / / Declare four v a r i a b l e s of
std2, std3; / / type Student .
std = new Student(); / / Create a new objec t belonging
/ / to the class Student , and
/ / s tore a reference to t h a t
/ / objec t i n the v a r i a b l e std .
std1 = new Student(); / / Create a second Student objec t
/ / and s tore a reference to
/ / i t i n the v a r i a b l e std1 .
std2 = std1; / / Copy the reference value i n std1
/ / i n t o the v a r i a b l e std2 .
std3 = null; / / Store a n u l l reference i n the
/ / v a r i a b l e std3 .
std.name = " John Smith "; / / Set values of some instance v a r i a b l e s .
std1.name = "Mary Jones ";
/ / ( Other instance v a r i a b l e s have d e f a u l t
/ / i n i t i a l values of zero . )
After the computer executes these statements, the situation in the computer’s
memory looks like this:
This picture shows variables as little boxes, labeled with the names of the variables.
Objects are shown as boxes with round corners. When a variable contains a
reference to an object, the value of that variable is shown as an arrow pointing to the
object. The variable std3, with a value of null, doesn’t point anywhere. The arrows
from std1 and std2 both point to the same object. This illustrates a Very Important
Point:
When one object variable is assigned to another, only a reference is copied.
The object referred to is not copied.
When the assignment “std2 = std1;” was executed, no new object was created.
Instead, std2 was set to refer to the very same object that std1 refers to. This has
some consequences that might be surprising. For example, std1.name and std2.name
are two different names for the same variable, namely the instance variable in the
object that both std1 and std2 refer to. After the string “Mary Jones” is assigned to
the variable std1.name, it is also be true that the value of std2.name is “Mary Jones”.
There is a potential for a lot of confusion here, but you can help protect yourself from
it if you keep telling yourself, “The object is not in the variable. The variable just
holds a pointer to the object.”
You can test objects for equality and inequality using the operators == and !=,
but here again, the semantics are different from what you are used to. The test
“if (std1 == std2)”, tests whether the values stored in std1 and std2 are the
same. But the values are references to objects, not objects. So, you are testing
whether std1 and std2 refer to the same object, that is, whether they point to the
same location in memory. This is fine, if its what you want to do. But sometimes,
what you want to check is whether the instance variables in the objects have the
same values. To do that, you would need to ask whether
std1.test1 == std2.test1 && std1.test2 == std2.test2 && std1.test3
== std2.test3 && std1.name.equals(std2.name)}
I’ve remarked previously that Strings are objects, and I’ve shown the strings
“Mary Jones” and “John Smith” as objects in the above illustration. A variable of type String can only hold a reference to a string, not the string itself. It could also
hold the value null, meaning that it does not refer to any string at all. This explains
why using the == operator to test strings for equality is not a good idea.
The fact that variables hold references to objects, not objects themselves, has a
couple of other consequences that you should be aware of. They follow logically, if
you just keep in mind the basic fact that the object is not stored in the variable. The
object is somewhere else; the variable points to it.
Suppose that a variable that refers to an object is declared to be final. This
means that the value stored in the variable can never be changed, once the variable
has been initialized. The value stored in the variable is a reference to the object. So
the variable will continue to refer to the same object as long as the variable exists.
However, this does not prevent the data in the object from changing. The variable
is final, not the object. It’s perfectly legal to say
final Student stu = new Student();
stu.name = " John Doe"; / / Change data i n the objec t ;
/ / The value stored i n stu i s not changed !
/ / I t s t i l l r e f e r s to the same objec t .
Next, suppose that obj is a variable that refers to an object. Let’s consider what
happens when obj is passed as an actual parameter to a method. The value of obj
is assigned to a formal parameter in the method, and the method is executed. The
method has no power to change the value stored in the variable, obj. It only has a
copy of that value. However, that value is a reference to an object. Since the method
has a reference to the object, it can change the data stored in the object. After the
method ends, obj still points to the same object, but the data stored in the object
might have changed. Suppose x is a variable of type int and stu is a variable of type
Student. Compare:
void dontChange(int z) { void change(Student s) {
z = 42; s.name = " Fred ";
} }
The lines: The lines:
x = 17; stu.name = " Jane";
dontChange(x); change(stu);
System.out.println(x); System.out.println(stu.name);
outputs the value 17. outputs the value " Fred ".
The value of x is not The value of stu is not changed ,
changed by the method, but stu.name is.
which is equivalent to This is equivalent to
z = x; s = stu;
z = 42; s.name = " Fred ";

Enums and for-each Loops

Java 5.0 introduces a new “enhanced” form of the for loop that is designed to be
convenient for processing data structures. A data structure is a collection of data
items, considered as a unit. For example, a list is a data structure that consists
simply of a sequence of items. The enhanced for loop makes it easy to apply the
same processing to every element of a list or other data structure. However, one of
the applications of the enhanced for loop is to enum types, and so we consider it
briefly here.
The enhanced for loop can be used to perform the same processing on each of the
enum constants that are the possible values of an enumerated type. The syntax for
doing this is:
for ( enum−type−name variable−name : enum−type−name.values() )
statement
or
for ( enum−type−name variable−name : enum−type−name.values() ) {
statements
}
If MyEnum is the name of any enumerated type, then MyEnum.values() is a method
call that returns a list containing all of the values of the enum. (values() is a static
member method in MyEnum and of any other enum.) For this enumerated type, the
for loop would have the form:
for ( MyEnum variable−name : MyEnum.values() )
statement
The intent of this is to execute the statement once for each of the possible values of
the MyEnum type. The variable-name is the loop control variable. In the statement,
it represents the enumerated type value that is currently being processed. This variable
should not be declared before the for loop; it is essentially being declared in the
loop itself.
To give a concrete example, suppose that the following enumerated type has been
defined to represent the days of the week:
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
Then we could write:
for ( Day d : Day.values() ) {
System.out.print( d );
System.out.print(" i s day number ");
System.out.println( d.ordinal() );
}
Day.values() represents the list containing the seven constants that make up the
enumerated type. The first time through this loop, the value of d would be the first
enumerated type value Day.MONDAY, which has ordinal number 0, so the output
would be “MONDAY is day number0”. The second time through the loop, the value
of d would be Day.TUESDAY, and so on through Day.SUNDAY. The body of the loop
is executed once for each item in the list Day.values(), with d taking on each of those
values in turn. The full output from this loop would be:
MONDAY is day number 0
TUESDAY is day number 1
WEDNESDAY is day number 2
THURSDAY is day number 3
FRIDAY is day number 4
SATURDAY is day number 5
SUNDAY is day number 6
Since the intent of the enhanced for loop is to do something “for each” item in a
data structure, it is often called a for-each loop. The syntax for this type of loop is
unfortunate. It would be better if it were written something like “foreach Day d in
Day.values()”, which conveys the meaning much better and is similar to the syntax
used in other programming languages for similar types of loops. It’s helpful to think
of the colon (:) in the loop as meaning “in.”