Java Software Solutions Chapter 5 Enhancing Classes 1 References Revisited Object reference variables An object reference variable stores the address of an object. We use the dot operator to invoke an object’s method. The address in the reference variable is used to locate the representation of the object in memory In order to look up the appropriate method so we can invoke that method. 2 The null Reference A reference variable that does not currently point to an object is called a null reference. An instance variable has a null reference for its value when it is initially declared. If we try to follow a null reference, a NullPointerException is thrown. The identifier null is a reserved word. We can use it to check whether an instance variable currently points to an object. 3 Checking an Instance Variable If name is an instance variable, we could use the following code to avoid following a null reference: if (name == null) System.out.println(“Invalid name”); else System.out.println(name.length()); 4 The this Reference this is a reserved word that allows an object to refer to itself. Inside a method, the this reference can be used to refer to the currently executing object. if the following code were part of a method called move(): if (this.position == piece2.position) result = false; Then if move() were invoked by bishop1.move(); this would refer to bishop1, but if move() were invoked by bishop2.move(); , this would refer to bishop2. 5 Another use for this You can also use the keyword this to eliminate the need for different names for instance variables and method parameters. Assume the following method is in a class with instance variables called name, acctNumber, and balance. The assignments would be ambiguous if it were not for the keyword this. public Account(String name, long acctNumber, double balance) { this.name = name; this.acctNumber = acctNumber; this.balance = balance; } 6 Aliases Object reference variables store the address of the object they represent, not the object itself. Thus you must be careful when using assignment statements for objects. Consider the assignments ChessPiece bishop1 = new ChessPiece(); ChessPiece bishop2 = new ChessPiece(); bishop1 and bishop2 now hold the addresses of two different chess pieces, but if we then make the assignment bishop2 = bishop1; Now bishop1 and bishop2 point to (hold the address of) the same chess piece. We can no longer use bishop2 to access the chess piece it originally pointed to. bishop1 and bishop2 are now aliases for one another. 7 An Implication of Aliases If we have two reference variables that are aliases for the same object and we use one variable to change the state of the object, the state is also changed for the other variable since there is really only one object. In the previous example, if you use bishop1 to change the board position of bishop1, the board position of bishop2 also is changed. We need to be careful since inadvertent creation of aliases can produce unexpected and undesirable consequences. 8 Another Implication of Aliases With primitive data, the == operator works as expected to compare two values for equality. But with objects, == returns true only if the two reference variables being compared are aliases of each other. Every object has a method called equals() obtained by inheritance from the object class. But unless you specifically create the equals() method for a specific class (overriding the inherited equals() method), it works just like the == operator. Note: we discuss inheritance in detail in Ch 7. 9 Additional Comment about equals( ) If you were writing the code for a bishop class, you could include the code for an equals() method that will compare two different bishop objects (such as bishop1 and bishop2) to see if they have advanced to the same row (your condition for equality) on the chess board. It would be important that during program execution your code doesn’t inadvertently cause bishop1 and bishop2 to become aliases; because if they did, your equals() method would always return true. Since bishop1 and bishop2 would be pointing to the same bishop object. 10 Garbage When during program executions, an object that has been created no longer has a reference variable with its address, that object can no longer be accessed by the program. As was mentioned on an earlier slide, this could happen due to inadvertent creation of an alias. The object is called garbage since it can no longer serve any useful purpose in the program. 11 Garbage Collection Java performs automatic garbage collection. When the last reference to an object is lost, the object becomes a candidate for garbage collection. Occasionally, the Java runtime environment makes available the memory allocated to objects that were subsequently marked for garbage collection. In other languages, such as C, the programmer must write code to make this happen. 12 The finalize() Method If there is something that a programmer wants to accomplish in conjunction with an object being destroyed (garbage collection), the programmer can define a method called finalize() in the object’s class. finalize() takes no arguments and has a void return type. It will be executed by the Java runtime after the object is marked for garbage collection and before it is actually destroyed. finalize() is useful for closing files (discussed in Chapter 8). 13 Passing Parameters to Methods Java passes all parameters by passing the values in the actual parameters to the invoked method’s formal parameters. Parameter passing is, in effect, assignment statements, assigning to the formal parameters copies of the values stored in the invoking method’s actual parameters. Since the formal parameter holds a separate copy of the value that is passed in, any changes to the formal parameter in the called method have no effect on the actual parameter in the calling method. 14 Passing Objects as Parameters However, when an object is passed to a method, what is actually passed is the address (reference) to the object. The formal parameter and the actual parameter become aliases for each other. If we change the state of the object through a formal parameter reference inside the method, we are also changing the state of the object referenced by the actual parameter. Because they are the same object. 15 Changing the Value in a Formal Reference Parameter If we change the address in a formal parameter to make the parameter refer to a different object, the actual parameter will still refer to the original object. Now changes to the state of the object pointed to by the formal parameter will no longer change the state of the object pointed to by the invoking method’s actual parameter. Note: this not the same as using the address of the object to change the original object’s state. 16 Instance versus Local Variables Local variables are declared inside a method. They only exist in memory while the method in which they are declared is executing. Once execution of the method ends, the local variables no longer exist. Note: Formal parameters are, in effect, local variables Instance variables are declared in a class, but not inside a method. Each object that is created during program execution has memory space for its own instance variables. 17 Static or Class Variables Another kind of variable, called a static variable or class variable, is shared among all instances of a class. There is only one copy of a static variable for all objects of a class. Therefore, changing the value of a static variable during program execution changes it for all existing objects from that class. Memory for a static variable is established when the class that contains it is referenced for the first time in a program. A local variable in a method cannot be static. 18 Declaring static Variables The reserved word static is used as a modifier to declare a static variable. private static int count = 0; The above declaration declares a variable named count that is a private, static, integer variable. Constants, which are declared using the final modifier, are also often declared using the static modifier as well. Since the value of constants can’t change, only one copy is needed. 19 Static Methods In chapter 2, we learned that the methods of the math class are static methods, meaning they can be invoked through the class name. No math object need be instantiated. A method is made static by using the static modifier in the method declaration. The main() method of a Java program must declared with the static modifier. So it can be executed by the interpreter without instantiating an object from the class that contains main(). 20 Restrictions on static Methods Because static methods do not operate in the context of a particular object, they cannot reference instance variables. The compiler will issue an error if a static method attempts to use a nonstatic variable. A static method can, however, reference static variables because static variables exist independent of specific objects. The main() method, therefore, can access only static or local variables. 21 Wrapper Classes In Java there are primitive types (int, double, etc.) in addition to classes and objects. For each primitive type in Java there exists a corresponding wrapper class defined in the java.lang package. The names of the wrapper classes are mostly the same as those of the corresponding primitive classes, except they begin with an upper case letter. The wrapper classes provide methods related to management of the associated primitive type. See figure 5.4 on page 286 and appendix M. 22 Wrapper Classes There is a wrapper class in the java.lang package for each primitive type: Primitive Type byte Wrapper Class Byte short Short int Integer long Long float Float double Double char Character boolean Boolean void Void 23 static Methods and Constants in Wrapper Classes Wrapper classes contain static methods that can be invoked independent of any instantiated object. The Integer class contains a static method called parseInt() to convert an integer that is stored in a String to its corresponding int value. num = Integer.parseInt(str); Wrapper classes often contain static constants. The Integer class contains two static constants, MIN_VALUE and MAX_VALUE, which hold the smallest and largest int values. Other wrapper classes contain similar static methods and constants. 24 Nested Classes A class written inside another class is called a nested class. A nested class produces a bytecode file whose name is the name of the enclosing class followed by a $ character followed by the name of the nested class. If a class called Nested is declared inside a class called Enclosing, compiling them will result in two bytecode files called: Enclosing.class and Enclosing$Nested.class 25 Characteristics of Nested Classes Because it is a member of the enclosing class, a nested class has access to the enclosing class’s instance variables and methods. Even if they are declared as private. However, the enclosing class can directly access data in the nested class only if the data is declared public. It is reasonable to declare the data of a private nested class public because only the enclosing class can get to that data. This is an exception to the normal rule that public data violates encapsulation. 26 Use of Nested Classes A class should be nested only if it makes sense in the context of the enclosing class. When nesting reinforces the relationship between enclosing and nested classes while simplifying the implementation by allowing direct access to the data. The static modifier can be applied to a class, but only if the class is nested inside another. Like static methods, a static nested class cannot reference instance variables or methods defined in its enclosing class. 27 Inner Classes A nonstatic nested class is called an inner class. Because it is not static, an inner class is associated with each instance of the enclosing class. An instance of an inner class can exist only within an instance of the enclosing class. No member inside an inner class can be declared as static. Using inner classes with public data should be done only in situations in which the outer class is completely dependent on the inner class for its existence. 28 Interfaces A Java interface is a collection of constants and abstract methods. An abstract method is a method that does not have an implementation. There is no body. The header of the method, including the parameter list, is simply followed by a semicolon. An interface cannot be instantiated. An abstract method can be preceded by the reserved word abstract, though in interfaces it usually is not (since all methods in an interface are abstract, the word would be redundant). Methods in interfaces have public visibility by default. 29 Implementing Interfaces When a class implements an interface, the class must implement all of the methods specified by the interface. The class can also have other methods. A class implements an interface by providing method implementations for each of the abstract methods specified in the interface. See pages 294 thru 299 of our text for an interface, a class that implements the interface, and a program that uses the class that implements the interface. 30 The UML Diagram for an Interface <<interface>> MiniQuiz Complexity + main(args: String[]): void 1 + getComplexity() : int + setComplexity(int) : void 2 Question + getQuestion() : String + getAnswer() : String + answerCorrect(String) : boolean + toString() : String 31 The Comparable interface The Java standard class library contains interfaces as well as classes. The Comparable interface, for example, is defined in the java.lang package and contains only one method, compareTo(). The intention is to provide a common mechanism for comparing one object to another. It is up to the designer of each class to decide what it means for one object of that class to be less than, equal to, or greater than another object of the class. 32 Using the compareTo() Method One object calls the method and passes another object as a parameter: Example: if (obj1.compareTo(obj2) < 0) System.out.println(“obj1 is less than obj2”); The integer that is returned from the compareTo() method should be negative if obj1 is less than obj2, 0 if they are equal, and positive if obj1 is greater than obj2. It is up to the programmer to implement the compareTo() method. 33 The Iterator interface The Iterator interface is used by classes that represent a collection of objects. Its methods provide a means of moving through the collection one object at a time. The two primary methods in the Iterator interface are hasNext() which returns a boolean result and next() which returns an object. Another method, remove() , can be used to remove from the collection the object that was most recently returned by the next() method. 34