In this article, we will continue our in depth look at Java Classes. In this article we will continue our exploration of inheritance and interfaces. We will look into abstract classes and the casting objects as well as reviewing interfaces in Java,. This is part of a larger series of articles to help you prepare for the java associate exam.

The Value of Abstract Classes

Inheritance plays a very important part of object-oriented programming. It enables you to create a new class based on a class that has already been defined. The class that you use as the base for a new class can be either one that you have defined such as a standard class in Java, or a class defined by someone else maybe from a package supporting a specialized application area. In the Animal class, from our previous article, “Tutorial:In Depth View of Java Classes for the Java Certification Exam III”, we have introduced a a sound() method that did nothing because we wanted the call to the sound() method in the subclass objects dynamically. The method sound() has no meaning in the context of the generic class Animal, so it does not make much sense to implement it. This situation often arises in object-oriented programming. You will often find yourself creating a superclass from which you will derive a number of subclasses, just to take advantage of polymorphism.

In order to facilitate this programming strategy, Java has abstract classes as a feature. An abstract class is a class in which one or more methods are declared, but not defined. The bodies of these methods are omitted, because, as in the case of the method sound() in the Animal class, implementing the methods does not make sense. Because they have no definition and cannot be executed, they are called abstract methods. The declaration for an abstract method ends with a semicolon and you specify the method with the keyword abstract to identify it as such. To declare that a class is abstract you just use the keyword abstract in front of the class keyword in the first line of the class definition. The listing below shows the definition of the class Animal as an abstract class:

Java Code: Class Animal as abstract class
public abstract class Animal {
public abstract void sound();		// Abstract method

   public Animal(String aType) { 
      type = new String(aType);
   }

   public String toString() { 
      return “This is a “ + type;
   } 

   private String type;
}
It doesn't matter whether you prefix the class name with public abstract or abstract public; they are equivalent, but be consistent in your usage. The sequence public abstract is typically preferred. The same goes for the declaration of an abstract method, but both public and abstract must precede the return type specification, which is void in this case.
An abstract method cannot be private because a private method cannot be inherited and therefore cannot be redefined in a subclass. You cannot instantiate an object of an abstract class, but you can declare a variable of an abstract class type. With the new abstract version of the class Animal, you can still write:

Java Code: Declare a variable of type Animal
Animal thePet = null;
You can then use this variable to store objects of the subclasses, Cat, Siamese, Duck, and Guinea Pig.

When you derive a class from an abstract base class, it’s not necessary to define all the abstract methods in the subclass. In this case the subclass is also abstract so you cannot instantiate any objects of the subclass either. If a class is abstract, then you must use the abstract keyword when you define it, even if it only inherits an abstract method from its superclass. Sooner or later you must have a subclass that contains no abstract methods. You can then create objects of this class type.

The Base Class for Every Class

Every class that you define are subclasses by default of a standard class, Object, which is a superclass of every class. You never need to specify the class Object as a base in the definition of your classes as it happens automatically. Having Object as a universal superclass means a variable of type Object can store a reference to an object of any class type. This is useful when you want to write a method that needs to handle objects of unknown type. You can define a parameter to the method of type Object, in which case a reference to any type of object can be passed to the method. When necessary you can include code in the method to figure out what kind of object it actually is. As your classes inherit members from the class Object. The majority of the methods are public, and two are protected. The public methods are shown in the table below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam-d9-objectclassmethods.jpg
Table: Object Class Methods

Note that the getClass(), notify(), notifyAll(), and wait() methods cannot be overridden in your own class definitions they are fixed with the keyword final in the class definition for Object. It’s also clear why you could get polymorphic behavior with toString() in your derived classes since it is not defined in the base class. There is always a toString() method in all your classes that is inherited from Object. This means that ideally, we should have used the @Override annotation with this method in the Animal class, or indeed any class that implements toString(). The two protected methods that your classes inherit from Object are shown in the table below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam-d9-protectedobjectmethods.jpg
Table: Protected Object Class Methods

Everyone of your classes inherit the methods defined in the Object class. The details of the most important methods are discussed below.

The toString() Method

We discussed the use of the toString() method and it use by the compiler to obtain a String representation of an object when necessary. You must always declare the toString() method as public in a class. The listing below gives an example of the output for an Animal object:

XML Code: Typical Sample of Output
Your choice: 
Siamese@b75778b2 
It’s Tigger the Siamese 
Miao Miao
The second line here is generated by the toString() method implemented in the Object class. This is inherited in the Animal class, and it is called because you no longer override it. The hexadecimal digits following the @ in the output are the hashcode of the object, which is produced by the hashcode() method that is inherited from Object.

How to Determine the Type of an Object

The getClass() method that all your classes inherit from Object returns an object of type Class that identifies the class of an object. Suppose you have a variable pet of type Animal that might contain a reference to an object of type Dog, Cat, Duck, or even Guinea Pig. To figure out what sort of thing it really refers to, you could write the following statements:

Java Code: Determining Type of Object
Class objectType = pet.getClass();	// Get the class type 
System.out.println(objectType.getName());	// Output the class name
The method getName() is a member of the Class class, and it returns the fully qualified name of the actual class of the object for which it is called as a String object. Thus, the second statement outputs the name of the class for the pet object. If pet referred to a Guinea Pig object, this would output:

XML Code: Output of Object Name
Guinea Pig
This is the fully qualified name in this case, as the class is in the default package, which has no name. For a class defined in a named package, the class name would be prefixed with the package name. If you just wanted to output the class identity, you need not explicitly store the Class object. You can combine both statements into one:

Java Code: Output the class name
System.out.println(pet.getClass().getName());
This will produce the same output as before. Remember that the Class object returns the actual class of an object. Suppose you define a String object like this:

Java Code:
String saying = “A stitch in time saves nine.”;
You could store a reference to this String object as type Object:

Java Code:
Object str = saying;
The following statement displays the type of str:

Java Code:
System.out.println(str.getClass().getName());
This statement outputs the type name as java.lang.String. The fact that the reference is stored in a variable of type Object does not affect the underlying type of the object itself.
Although you can use the getClass() method to get the Class object corresponding to a particular class or interface type, there is a more direct way. If you append .class to the name of any class, interface, or primitive type, you have a reference to the Class object for that class.

Duplicating Existing Objects

The protected method clone() that is inherited from the Object class creates a new object that is a copy of the current object. It does this only if the class of the object to be cloned indicates that cloning is acceptable. This is the case if the class implements the Cloneable interface.

The clone() method that is inherited from Object clones an object by creating a new object of the same type as the current object and setting each of the fields in the new object to the same value as the corresponding fields in the current object. When the data members of the original object refer to class objects, the objects referred to are not duplicated when the clone is created—only the references are copied from the fields in the old object to the fields in the cloned object. This isn't typically what you want to happen—both the old and the new class objects can now be modifying a single shared mutable object that is referenced through their corresponding data members, not recognizing that this is occurring.

Using the clone() method to duplicate objects can be complicated and cumbersome. If you need to clone objects of your class types, the simplest approach is to ignore the clone() method and implement a copy constructor in your class. A copy constructor is just a constructor that duplicates an object that is passed as an argument to it.

Methods Accepting a Variable Number of Arguments

In Java, it is also possible to write a method that accepts an arbitrary number of arguments when it is called, and the arguments that are passed do not need to be of the same type. Such methods are called varargs methods. Understanding how this works depends on having an understanding of the role of the Object class. A method accepts a variable number of arguments by specifying the last parameter as follows:

XML Code:
Object ... args
The method can have zero or more parameters preceding this, but this must be last for obvious reasons. The ellipsis (i.e. three periods) between the type name Object and the parameter name args enables the compiler to determine that the argument list is variable. The parameter name args represents an array of type Object[], and the argument values are available in the elements of the array as type Object. Within the body of the method, the length of the args array tells you how many arguments were supplied. An example of a static method accepting any number of arguments would look like the following:

Java Code: Example of Function with many arguments
public static void printAll(Object ... args) { 
   for(Object arg : args) {
      System.out.print(“ “ + arg); 
   }
   System.out.println();
}
The arguments can be anything. Values of primitive types are autoboxed because the method expects reference arguments. The loop outputs the string representation of each of the arguments on a single line, the string being produced by invoking the toString() method for whatever the argument is. You don't have to specify the type of the variable argument list as type Object; you can specify it as any class or interface type. The arguments must be of the type that you specify, or any subtype of that type. Specifying the type of the variable argument list as Object maximizes flexibility because any types of argument can be supplied, but there may be occasions where you want to restrict the types of the arguments that can be supplied.

Casting Objects Up or Down

You can cast an object to another class type, but only if the current object type and the new class type are in the same hierarchy of derived classes, and one is a superclass of the other. For example, earlier in this chapter you defined the classes Animal, Cat, Siamese, PetCat, Cat, and Duck, and these are related in the hierarchy shown in the figure below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam-d9-classhierarchy.jpg
Figure: Class Hierarchy

You can cast a reference to an object of a given class type upwards through its direct and indirect superclasses. For example, you could cast a reference to an object of type Siamese directly to type Cat, type Animal, or type Object. You could write:

Java Code: Casting an Object
Siamese aPet = new Siamese(“Indy”); 
Animal theAnimal = (Animal)aPet;	// Cast the Siamese to Animal
When you are assigning an object reference to a variable of a superclass type, you do not have to include the cast. You could write the assignment as:

Java Code: Cast the Siamese to Animal
Animal theAnimal = aPet;
When you cast an object reference to a superclass type, Java retains full knowledge of the actual class to which the object belongs. If this were not the case, polymorphism would not be possible. Because information about the original type of an object is retained, you can cast down a hierarchy as well. However, you must always write the cast explicitly because the compiler is not prepared to insert it. For the cast to work, the object must be a legitimate instance of the class you are casting to. In other words the class you are casting to must be the original class of the object, or must be a superclass of the object.For example, a cast the Animal to type Cat, would look like the following:

Java Code: Cast from Animal to Cat
Cat aCat = (Cat)theAnimal;
Now the variable aCat refers to an object of type Siamese that also happens to be a Cat. Remember, you can only use the variable aCat to call the polymorphic methods from the class Siamese that override methods that exist in Cat. You can't call methods that are not defined in the Cat class. If you want to call a method that is in the class Siamese and not in the class Cat, you must first cast aCat to type Siamese.

Determining the Time to Cast Objects

There are valid reasons to cast objects in both directions through a class hierarchy such as whenever you execute methods polymorphically, you are storing objects in a variable of a base class type and calling methods in a derived class. This generally involves casting the derived class objects to the base class. Another reason for casting up through a hierarchy is to pass an object of several possible subclasses to a method. By specifying a parameter as a base class type, you have the flexibility to pass an object of any derived class to it. You could pass a Cat, Duck, or Cat object to a method as an argument for a parameter of type Animal, for example.

Identifying Objects

There are circumstances when you may not know exactly what sort of object you are dealing with. This can arise if a derived class object is passed to a method as an argument for a parameter of a base class type for example, in the way that I discussed in the previous section. A parameter of type Animal could have a Duck, a Cat, or a Flea object passed as the argument. In some situations you may need to cast the object to its actual class type, perhaps to call a class-specific method. If you try to make the cast and it turns out to be illegal, an exception is thrown, and your program ends unless you have made provision for catching the exception. One way to obviate this situation is to verify that the object is of the type you expect before you make the cast.

You could use the getClass() method to obtain the Class object corresponding to the class type, and then compare it to a Class instance for the class you are looking for. You can also do this using the instanceof operator. For example, suppose you have a variable pet of type Animal, and you want to cast it to type Duck. You could code this as:

Java Code: Identifying an Object
if(pet instanceof Duck) { 
   Duck aDuck = (Duck)pet;	// It is a duck so the cast is OK 
   aDuck.layEgg();			// and You can have an egg for tea
}
If pet does not refer to a Duck object, an attempt to cast the object referenced by pet to Duck causes an exception to be thrown. This code fragment executes the cast and lay an egg only if pet does point to a Duck object. Generally you should always use the instanceof operator to check the type of a reference. You only need to resort to checking the Class object corresponding to a reference when you need to confirm the exact type of the reference.

Enhancements to Enumerations

You can put the definition of an enumeration type in the definition of a class or in a separate source file. In the second case you specify the name of the file containing the enumeration type definition in the same way as for any other class type. An enumeration that you define in its own source file can be accessed by any other source file in exactly the same way as any other class definition.

An object representing an enumeration constant also stores an integer field. By default, each constant in an enumeration is assigned an integer value that is different from all the others. The values are assigned to the enumeration constants in the sequence in which you specify them, starting with zero for the first constant, one for the second, and so on. Although you generally don’t need to do this, you can retrieve the value for a constant by calling its ordinal() method. Enumerations allows you to compare values of an enumeration type for equality using the equals() method. For example, assuming that you have defined an enumeration type, Season, with enumeration constants spring, summer, fall, and winter, you could write the following:

Java Code: Enumerator Comparison Example
Season now = Season.winter; 
if(now.equals(Season.winter))
   System.out.println(“It is definitely winter!”);
The equals() method is inherited from the Enum class in your enumeration class type. Your enumeration class type also inherits the compareTo() method that compares instances of the enumeration based on their ordinal values. It returns a negative integer if the value for the instance for which the method is called is less than the instance that you pass as the argument, 0 if they are equal, and a positive integer if the value of the current instance is greater than the value for the argument. Thus, the sequence in which you specify the enumeration constants when you define them determines the order that the compareTo() method implements. An example of using the compareTo() method is shown below:

Java Code: CompareTo Example
if(now.compareTo(Season.summer) > 0) 
   System.out.println(“It is definitely getting colder!”);
The values() method for an enumeration is a static member of your enumeration class type. This method returns a collection object containing all the enumeration constants that you can use in a collection-based for loop.

Increasing Members in an Enumeration Class

Because an enumeration is a class, you have the possibility to add your own methods and fields when you define the enumeration type. You can also add your own constructors to initialize any additional fields you introduce. For example, if you define an enumeration for clothing sizes of something like jackets, your initial definition would be the following:

Java Code: Enumeration Example
public enum JacketSize { small, medium, large, extra_large, extra_extra_large }
You then realize that you would really like to record the average chest size applicable to each jacket size. You could amend the definition of the enumeration like this:

Java Code:
public enum JacketSize { 
   small(36), medium(40), large(42), extra_large(46), extra_extra_large(48);

   // Constructor 
   JacketSize(int chestSize) {
      this.chestSize = chestSize;
   } 

   // Method to return the chest size for the current jacket size 
   public int chestSize() {
      return chestSize; 
   }

   // Field to record chest size
   private int chestSize;
}
Note how the list of enumeration constants now ends with a semicolon. Each constant in the list has the corresponding chest size between parentheses, and this value is passed to the constructor that you have added to the class. In the previous definition of JacketSize, the appearance of each enumeration constant results in a call to the default constructor for the class. In fact, you could put an empty pair of parentheses after the name of each constant, and it would still compile. However, this would not improve the clarity
of the code. Because you have defined a constructor, no default constructor is defined for the enumeration class, so you cannot write enumeration constants just as names. You must put the parentheses enclosing a value for the chest size following each enumeration constant. Of course, if you want to have the option of omitting the chest size for some of the constants in the enumeration, you can define your own default constructor and assign a default value for the chestSize field.

How to Design Classes

A basic problem in object-oriented programming is deciding the relationship between the various classes in your program. One possibility is to create a hierarchy of classes by deriving classes from a base class that you have defined and adding methods and data members to specialize the subclasses. We have already made an example of this with the Animal class and the subclasses derived from it. Another means is by defining a set of classes that is not dependent on a hierarchy but that have data members that are themselves class objects. For example, a Zoo class might well have objects of types derived from Animal as members, for example. You can have class hierarchies that contain data members that are class objects you already have this with the classes derived from Animal because they have members of type String. There are no clear-cut answers or rules for design classes using object-oriented programming, but there are some guidelines and some contexts in which the answer may be more obvious.

Aside from the desirability of reflecting real-world relationships between types of objects, the need to use polymorphism is a primary reason for using subclasses or interfaces. This is the essence of object-oriented programming. Having a range of related objects that can be treated equivalently can greatly simplify your programs. You have seen how having various kinds of animals specified by classes derived from a common base class, Animal, enables us to act on different types of animals as though they are the same, producing different results depending on what kind of animal is being dealt with, and all this automatically.

A Simple Example of Object Oriented Design

Many situations involve making judgments about the design of your classes. The approach depends on your personal preference. Consider a simple example where you want to define a class PolyLine to represent geometric entities that consist of a number of connected line segments, as illustrated in the figure below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam-d9-polylines.jpg
Figure: Polylines

The figure above shows two polylines, one defined by four points, the other defined by six points. It seems reasonable to represent points as objects of a class Point. Points are well-defined objects that occur in the context of all kinds of geometric entities. You have seen a class for points earlier, which you put in the Geometry package. We will define what is required in the listing below:

Java Code: Class Point
public class Point { 
   // Create a point from its coordinates 
   public Point(double xVal, double yVal) {
      x = xVal; 
      y = yVal;
   }

   // Create a point from another point 
   public Point(Point point) {
      x = point.x; 
      y = point.y;
   }

   // Convert a point to a string 
   @Override 
    public String toString() {
       return x+”,”+y;
    }

    // Coordinates of the point 
    protected double x; 
    protected double y;
}
In the listing above, both data members of Point are inherited in any subclass because they are specified as protected. They are also insulated from interference from outside the package containing the class. The toString() method enables Point objects to be concatenated to a String object for automatic conversion for example in an argument passed to the println() method.

The next question needing an answer is "Should I derive the class PolyLine from the class Point?" The answer should be obvious as a polyline is not a kind of point, so one cannot logical derive the a PolyLine class from the Point class. Only when you can say that one kind of object is a specialized form of another kind of object, do you have a good case for a derived class. This is always the case, but is generally true.

The final Modifier

You have already used the final keyword to fix the value of a static data member of a class. You can also apply this keyword to the definition of a method, and to the definition of a class. The final modifier is used when you want to prevent a subclass from overriding a method in your class. Any attempt to override a final method in a subclass results in the compiler flagging the new method as an error. For example, you could declare the method addPoint() as final within the class PolyLine by writing its definition in the class as:

Java Code: AddPoint Method
public final void addPoint(Point point) {
   polyline.addItem(point);	
   // Add the point to the list
Any class derived from PolyLine is not able to redefine this method. Obviously, an abstract method } cannot be declared as final—because it must be defined in a subclass somewhere. If you declare a class as final, you prevent any subclasses from being derived from it. To declare the class PolyLine as final, you define it as:

Java Code: Final Class PolyLine
public final class PolyLine {
      // Definition as before...
}
If you now attempt to define a class based on PolyLine, you get an error message from the compiler. An abstract class cannot be declared as final because this prevents the abstract methods in the class from ever being defined. Declaring a class as final is a drastic step that prevents the functionality of the class being extended by derivation, so be clear as to the reasons you want to do this.

The Value of Interfaces

In the classes that you derived from the class Animal, you had a common method, sound(), that was implemented individually in each of the subclasses. The method signature was the same in each class, and the method could be called polymorphically. The main point to defining the class Animal first and then subsequently defining the classes Cat, Dog, etc, from it was to be able to get polymorphic behavior. When all you want is a set of one or more methods to be implemented in a number of different classes so that you can call them polymorphically, you can dispense with the base class altogether.

It is more efficient to achieve the same result by using a Java facility called an interface. The name indicates its primary use for specifying a set of methods that represent a particular class interface, which can be implemented appropriately in a number of different classes. All of the classes then share this common interface, and the methods in it can be called polymorphically through a variable of the interface type. This is just one aspect of what you can do using an interface.

An interface is basically a collection of related constants as well as abstract and normal methods. An interface doesn't define what a method does, it only defines its form, which consists of its name, its parameters, and its return type. This means that by definition the methods in an interface are abstract.

In order to use an interface, you must create a class to implement the interface in a class. This is done by declaring that the class implements the interface via the implements keyword and then you write the code for each of the methods that the interface declares as part of the class definition. When a class implements an interface, any constants that were defined in the interface definition are available directly in the class, just as though they were inherited from a base class. An interface can contain either constants, or abstract methods, or both. An example of an interface is shown below:

Java Code: Interface ConversionFactors
public interface ConversionFactors { 
double INCH_TO_MM = 25.4; 
double OUNCE_TO_GRAM = 28.349523125; 
double POUND_TO_GRAM = 453.5924; 
double HP_TO_WATT = 745.7;
double WATT_TO_HP = 1.0/HP_TO_WATT;
public static double poundsToGrams(double pounds); 
}
The methods in an interface are always public and abstract, so you do not need to specify them as such and you definitely cannot add any attributes other than the defaults, public and abstract. This implies that methods declared in an interface can never be static, so an interface always declares instance methods. The constants in an interface are always public, static, and final, so you do not need to specify the attributes for these either.

Interfaces are defined like classes, but using the keyword interface rather than the keyword class. You store an interface definition in a .java file with the same name as the interface. The name that you give to an interface must be different from that of any other interface or class in the same package. Just as for classes, the members of the interface appear between a pair of braces that delimit the body of the interface definition.
Using Anonymous Classes

There are occasions where you need to define a class for which you will only ever want to define one object in your program, and the only use for the object is to pass it directly as an argument to a method. In this case, as long as your class extends an existing class, or implements an interface, you have the option of defining the class as an anonymous class. The definition for an anonymous class appears in the new expression, in the statement where you create and use the object of the class, so that there is no necessity to provide a name for the class.

I illustrate how this is done using an example. Suppose you want to define an object of a class that implements the interface ActionListener for one-time use. You could do this as follows:

Java Code: addActionListener Method
pickButton.addActionListener(new ActionListener() { 
   // Code to define the class
   // that implements the ActionListener interface }
);
The class definition appears in the new expression that creates the argument to the addActionListener() method. This method requires a reference of type ActionListener—in other words, a reference to a class that implements the ActionListener interface. The parentheses following the name of the interface indicate you are creating an object reference of this type, and the details of the class definition appear between the braces. The anonymous class can include data members as well as methods, but obviously
not constructors because the class has no name. Here, all the methods declared in the ActionListener interface would need to be defined. You use this approach in practice when you are implementing window-based applications later in the book.

If the anonymous class extends an existing class, the syntax is much the same. In this case, you are calling a constructor for the base class, and if this is not a default constructor, you can pass arguments to it by specifying them between the parentheses following the base class name. The definition of the anonymous class must appear between braces, just as in the previous example.

An anonymous class can be convenient when the class definition is short and simple. You shouldn't use the approach to define classes of any complexity as it makes the code very difficult to understand.

Summary

That completes our coverage of polymorphism and Java classes. You will find that all the things you learned about Java classes will serve you well in the development of your Java programs.