In this article, we will continue our in depth look at Java Classes. We will focus on how you can reuse existing classes by creating new classes based on the ones you have and explores the ramifications of using this facility, and the additional capabilities it provides. We will also look into polymorphism. This is part of a larger series of articles to help you prepare for the java associate exam.

Leveraging Existing Classes

A key aspect of object-oriented programming allow you to create a new class based on a class that has already been defined. The class that you use as the base for your new class can be one that you have defined, a standard class in Java, or a class defined by someone else—perhaps from a package supporting a specialized application area.

Defining a new class based on an existing class is called derivation. The new class, or derived class, is referred to as a direct subclass of the class from which it is derived. The original class is called a base class because it forms the base for the definition of the derived class. The original class is also referred to as a superclass of the derived class. You can also derive a new class from a derived class, which in turn was derived from some other derived class, and so on. This is illustrated in the figure below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam III-d8-derivedclasses.jpg
Figure: Derived Classes

This figure shows just three classes in a hierarchy, but there could be as many as you like. If we use a more concrete example, it might help to clarify this concept. So let’s define a class Cat that could represent a Cat of any kind:

Java Code:
class Cat { 
   // Members of the Cat class...
}
This might contain a data member identifying the name of a particular Cat, such as Tomcat or Tigger, and another data member to identify the breed, such as Bengal or Persian. From the Cat class, you could derive a Siamese class that represented Cats that were siameses:

Java Code: Derived Class
class Siamese extends Cat { 
   // Members of the Siamese class...
}
The extends keyword that you use here identifies that Cat is a base class for Siamese, so an object of type Siamese has members that are inherited from the Cat class, in addition to the members of the Siamese class that appear in its definition. The breed is Siamese for all instances of the class Siamese, although in general the name for each siamese may be different. The Siamese class might have some additional data members that characterize the specifics of what it means to be a siamese. You see in a moment how you can arrange for the base class data members to be set appropriately.

A Siamese object is a specialized instance of a Cat object. This reflects real life. A siamese is obviously a cat and has all the properties of a basic cat, but it has some unique characteristics of its own that distinguish it from all the cats that are not siamese. The inheritance mechanism that adds all the properties of the base class, Cat to those in the derived class is a good model for the real world. The members of the derived class define the properties that differentiate it from the base type, so when you derive one class from another, you can think of your derived class as a specification for objects that are specializations of the base class object. Another way of thinking about this is that the base class defines a set of objects and a derived class defines a specific subset of those that have particular defining characteristics.

Understanding Class Inheritance

When you derive a new class from a base class, the process is additive in terms of what makes up a class definition. The additional members that you define in the new class establish what makes a derived class object different from a base class object. Any members that you define in the new class are in addition to those that are already members of the base class. For your Siamese class that you derived from Cat, the data members to hold the name and the breed that are defined for the class Cat are automatically in the class Siamese. A Siamese object always has a complete Cat object inside it as well as all its data members and methods. This does not mean that all the members defined in the Cat class are available to methods that are specific to the Siamese class. Some are and some aren't. The inclusion of members of a base class in a derived class so that they are accessible in that derived class is called class inheritance. An inherited member of a base class is one that is accessible within the derived class. If a base class member is not accessible in a derived class, then it is not an inherited member of the derived class, but base class members that are not inherited still form part of a derived class object.

An inherited member of a derived class is a full member of that class and is freely accessible to any method in the class. Objects of the derived class type contain all the inherited fields and methods of the base class as well as the members that are specific to the derived class. Note that a derived class object always contains a complete base class object within it, including all the fields and methods that are not inherited. To better understand this we will look at how inheritance works and how the access attribute of a base class member affects its visibility in a derived class.

You need to consider several aspects of defining and using a derived class. First, you need to know the members of the base class that are inherited in the derived class. What this implies for both the data members and methods is that there are some subtleties that you need to understand. When you create an object of the derived class, there are some aspects of inheritance in this context that requires closer consideration. We will first look at the data members that are inherited from a base class.

Data Member Inheritance

The figure below shows which access attributes are permitted for a class member to be inherited in a subclass. It shows what happens when the subclass is defined in either the same package or a different package from that containing the base class. Remember that inheritance implies accessibility of the member in a derived class, not just presence.

Tutorial:In Depth View of Java Classes for the Java Certification Exam III-d8-inheritanceaccessibility.jpg
Figure:Inheritance and Inaccessibility of Classes

In the figure above, a subclass that you define in the same package as its base class inherits everything except for private data members of the base. If you define a subclass outside the package containing the base class, the private data members are not inherited, and neither are any data members in the base class that you have declared without access attributes. Members defined as private in the base class are never inherited under any circumstances. The base class, MyClass, must be declared as public in Package1, otherwise it would not be accessible from Package2 as the base class for SubClass2.

You should also be able to see where the explicit access specifiers now sit in relation to one another. The public specifier is the least restrictive on class members because a public member is available everywhere, protected specifier comes next, and prevents access from classes outside of a package, but does not limit inheritance as long as the class itself is public. Putting no access specifier on a class member limits access to classes within the same package and prevents inheritance in subclasses that are defined in a different package. Due to this, we refer to class members without an access specifier as package-private. The most restrictive is private because access is constrained to the same class.

The inheritance rules equally apply to members of a class that have been declared as static as well as non-static members. Remember that only one occurrence of each static variable in a class exists and is shared by all objects of the class, whereas each object has its own set of instance variables. A variable that you would declare as private and static in the base class is not inherited in a derived class, whereas a variable that you declare as protected and static are inherited and are shared between all objects of a derived class type, as well as objects of the base class type.

Working with Hidden Data Members

You can define a data member in a derived class with the same name as a data member in the base class. Although this is not a recommended approach for class design, it's a possibility that can arise unintentionally. When it occurs, the base class data member may still be inherited, but it is hidden by the derived class member with the same name. The hiding mechanism applies regardless of whether the respective types or access attributes are the same or not. The base class member is hidden in the derived class if the names are the same.

Any use of the derived class member name always refers to the member defined as part of the derived class. To refer to the inherited base class member, you must qualify it with the keyword super to indicate it is the member of the superclass that you want. If you have a data member value as a member of the base class, and a data member with the same name in the derived class, then in the derived class, the name value references the derived class member, and the name super.value refers to the member inherited from the base class. Note that you cannot use super.super.something to refer to a member name hidden in the base class of a base class.

In most situations you don't need to refer to inherited data members in this way, since hopefully you would not deliberately set out to use duplicate names. This situation can commonly arise if you are using a class as a base that is subsequently modified by adding data members such as with a Java library class for some other class in a package designed and maintained by someone else. Since your code does not presume the existence of the base class member with the same name as your derived class data member, hiding the inherited member is precisely what you want. It enables the base class to be altered without breaking your code.

Working with Inherited Methods

Ordinary methods in a base class, by which I mean methods that are not constructors, are inherited in a derived class in the same way as the data members of the base class. Those methods declared as private in a base class are not inherited, and those that you declare without an access attribute are inherited only if you define the derived class in the same package as the base class. The rest are all inherited.

Constructors are different from ordinary methods. Constructors in the base class are never inherited, regardless of their attributes. You can look into the intricacies of constructors in a class hierarchy by considering how derived class objects are created.

Objects of a Derived Class

A derived class extends a base class. This is basic fact about inheritance. It really does do this. Remember that inheritance is about what members of the base class are accessible in a derived class, not what members of the base class exist in a derived class object. An object of a subclass contains all the members of the original base class, plus any new members that you have defined in the derived class. This is illustrated in the figure below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam III-d8-objectsofderivedclasses.jpg
Figure: Objects of a Derived Class

The base members are all there in a derived class object. You can't access some of them in the methods that are defined for the derived class. The fact that some of the base class members are inaccessible does not mean that they are they are not essential members of your derived class objects. A Siamese object needs all the Cat attributes that make it a Cat object, even though some of these may not be accessible to the Siamese methods. The base class methods inherited in a derived class can access all the base class members, including those that are not inherited.

We can call the base class constructors, although they are not inherited in your derived class in order to initialize the base class members. Note that if you don't call a base class constructor from your derived class constructor, the compiler will try to arrange to do it for you. The reasoning behind this is that because a derived class object has a base class object inside it, a good way to initialize the base part of a derived class object is using a base class constructor. To understand this better, let’s see how a derived class is constructed in practice.

Process of Deriving a Class

In this simple example we have defined a class to represent an animal as follows:

Java Code: Animal Class
public class Animal { 
   public Animal(String aType) {
      type = new String(aType);
   }

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

   private String type;
}
This has a member, type, to identify the type of animal, and its value is set by the constructor. It is private and is therefore not inherited in a class derived from Animal. You also have a toString() method for the class to generate a string representation of an object of the class.

It is now possible to define another class, based on the class Animal such as cats. You are able to do this immediately, without affecting the definition of the class Animal. You could write the basic definition of the class Cat in the following manner:

Java Code: Cat Class Derived from Animal Class
public class Cat extends Animal { 
   // constructors for a Cat object

   protected String name; 			// Name of a Cat
    protected String breed;		// Cat’s breed
}
The keyword, extends, shown in the definition of a subclass is used to identify the name of the direct superclass. The class Cat inherits only the method toString() from the class Animal, because the private data member and the constructor cannot be inherited. A Cat object has a type data member that needs to be set to “Cat”; it can't be accessed by methods that you define in the Cat class. You have added two new instance variables in the derived class. The name member holds the name of the particular cat, and the breed member records the kind of cat it is. These are both protected and therefore are accessible in any class derived from Cat. All you need to add is the means of creating Cat class objects.

Using Derived Class Constructors

You can define two constructors for the subclass Cat, one that just accepts an argument for the name of a Cat and another that accepts both a name and the breed of the Cat object. For any derived class object, the private base class member, type, must be properly initialized. This is done by calling a base class constructor from the derived class constructor:

Java Code:
public class Cat extends Animal {
   public Cat(String aName) { 
      super(“Cat”); 				// Call the base constructor
      name = aName; 				// Supplied name
      breed = “Unknown”;				// Default breed value
   }

   public Cat(String aName, String aBreed) { 
      super(“Cat”); 				// Call the base constructor
      name = aName;				// Supplied name
      breed = aBreed;			// Supplied breed
   }

   protected String name; 			// Name of a Cat
   protected String breed;			// Cat breed
}
The statement in the derived class constructors that calls the base class constructor is the following:

Java Code: Call the base constructor
super(“Cat”);
The use of the super keyword here as the method name calls the constructor in the superclass or the direct base class of the class Cat (i.e. class Animal). This initializes the private member type to “Cat” because this is the argument passed to the base constructor. The superclass constructor is always called in this manner in the subclass by using the name super rather than the base class constructor name Animal. The super keyword has other uses in a derived class. You can access a hidden member of the base class by qualifying the member name with super keyword.

Using the Base Class Constructor

You should always call an appropriate base class constructor from the constructors in your derived class. The base class constructor call must be the first statement in the body of the derived class constructor. If the first statement in a derived class constructor is not a call to a base class constructor, the compiler will inserts a call to the default no-arg base class constructor for you:

Java Code: Call the default base constructor
super();
This can result in a compiler error despite the offending statement being inserted automatically. This come about because when you define your own constructor in a class, such as for the Animal class, no default constructor is created by the compiler. The assumption is made that you are handling all of the details of object construction, including any requirement for a default constructor. If you forget to define your own default no-arg constructor in a base class, when the compiler inserts a call to the default constructor from your derived class constructor, you will get a message saying that the constructor is not there.

Overriding a Base Class Method

You can define a method in a derived class that has the same signature as a method in the base class. This means that the method names must be the same and the parameter lists must contain the same number of parameters with identical types. The access attribute for the method in the derived class can be the same as that in the base class or it can be less restrictive, but it cannot be more restrictive. So if you then declare a method as public in the base class, any derived class definition of the method must also be declared as public. In this case, it is not possible to omit the access attribute or specify it as private or protected.

Defining a new version of a base class method in this manner will cause the derived class method to be called for a derived class object, and not the method inherited from the base class. The method in the derived class overrides the method in the base class. The base class method is still there. You can call it in a derived class. The listing below shows an example of the overriding method in a derived class:

You can add the definition of a new version of toString() to the definition of the derived class, Cat:

Java Code:
 public String toString() {
   return “It’s “ + name + “ the “ + breed;
}
With this change to the example, the output is now:

XML Code: Output
It’s Tigger the Tabby 
It’s Tomcat the Unknown
Using the @Override Annotation

When you define a method in a derived class that is intended to override a superclass method, it is easy to make a mistake in the signature for the derived class method. If the name and parameter list of your derived class method are not identical to that of the superclass method, you are defining an overload for the base class method, not an override. The @Override annotation is intended to protect you from this kind of error. The listing below shows you how to use the @Override annotation in the Cat class:

Java Code: Cat Class using @Override
public class Cat extends Animal { 
   public Cat(String aName) {
      super(“Cat”); 				// Call the base constructor
      name = aName; 			// Supplied name
      breed = “Unknown”;			// Default breed value
   }

   public Cat(String aName, String aBreed) { 
      super(“Cat”); 				// Call the base constructor
      name = aName; 			// Supplied name
      breed = aBreed;			// Supplied breed
   }

   // Present a cat’s details as a string
   @Override
   public String toString() { 
      return super.toString() + “\nIt’s “ + name + “ the “ + breed;
   }

   protected String name; 			// Name of a Dog
   protected String breed;			// Dog breed
}
There will be no error in the parameter list for the toString() method inherited from the Object class. But if you spell the name as ToString(), you will have just added a new method.

Any method you mark with the @Override annotation causes the compiler to verify that the signature of the method is the same as a method with the same name in a superclass. If it is not, you get an error message. It is therefore a good idea to use the @Override annotation for all your methods that override an inherited method.

Choosing Base Class Access Attrition

You know the options available for defining the access attributes for classes you expect to use to define subclasses.The effect the attributes have on class inheritance depends on what you want to do with your classes in the future. There are some basic object-oriented principles you should consider. These are the following:
  • You should declare the methods that make up the external interface to a class as public. As long as there are no overriding methods defined in a derived class, public base class methods are inherited and fully available as part of the external interface to the derived class. You should not normally make data members public unless they are constants intended for general use.
  • If you expect other people will use your classes as base classes, your classes will be more secure if you keep data members private, and provide public methods for accessing and manipulating them when necessary. In this way you control how a derived class object can affect the base class data members.
  • Making base class members protected allows them to be accessed from other classes in the same package, but prevents direct access from a class in another package. Base class members that are protected are inherited in a subclass and can, therefore, be used in the implementation of a derived class. You can use the protected option when you have a package of classes in which you want uninhibited access to the data members of any class within the same package—because they
  • operate in a closely coupled way, for instance—but you want free access to be limited to subclasses in other packages.
  • Omitting the access attribute for a class member makes it directly available to other classes in the same package while preventing it from being inherited in a subclass that is not in the same package—it is effectively private when viewed from another package.


Using Polymorphism

Class inheritance is not just about reusing classes that you have already defined as a basis for defining a new class. It also adds enormous flexibility to the way in which you can program your applications, with a mechanism called polymorphism. In programming terms polymorphism means the ability of a single variable of a given type to be used to reference objects of different types and to automatically call the method that is specific to the type of object the variable references. This enables a single method call to behave differently, depending on the type of the object to which the call applies. This is illustrated in the figure below:

Tutorial:In Depth View of Java Classes for the Java Certification Exam III-d8-polymorphic.jpg
Figure: Polymorphic Behavior

A few requirements must be fulfilled to get polymorphic behavior, so let's step through them.
First of all, polymorphism works with derived class objects. It also depends on a new capability that is possible within a class hierarchy that you haven't met before. Up to now you have always been using a variable of a given type to reference objects of the same type. Derived classes introduce some new flexibility in this. Of course, you can store a reference to a derived class object in a variable of the derived class type, but you can also store it in a variable of any direct or indirect base class type. More than that, a reference to a derived class object must be stored in a variable of a direct or indirect class type for polymorphism to work. For example, the figure illustrates how a variable of type Cat can be used to store a reference to an object of any type derived from Cat. If the Cat class were derived from the Animal class here, a variable of type Animal could also be used to reference Siamese, Persian, or Tabby objects.

Polymorphism means that the actual type of the object involved in a method call determines which method is called, rather than the type of the variable being used to store the reference to the object. In the figure above, if aCat contains a reference to a Siamese object, the bark() method for that object is called. If it contains a reference to a Collie object, the bark() method in the Collie class is called. To get polymorphic operation when calling a method, the method must be declared as a member of the base class—the class type of the variable you are using—as well as being declared as a member of the class type of the object involved. So in the example, the Cat class must contain a bark() method, as must each of the derived classes. You cannot call a method for a derived class object using a variable of a base class type if the method is not a member
of the base class. Any definition of the method in a derived class must have the same signature as in the base class and must have an access specifier that is no more restrictive.

Methods that have the same signature have the same name, and have parameter lists with the same number of parameters and corresponding parameters are of the same type. You have a bit more flexibility with the return type when you are defining a polymorphic method. For polymorphic behavior, the return type of the method in the derived class must either be the same as that of the base class method or must be of a type that is a subclass of the return type in the base class. Where the return types are different but the return type of the method in the derived class is a subclass of the return type in the base class, the return types are said to be covariant. Thus the type of object returned by the derived class method is just a specialization of the type returned by the base class method. For example, suppose that you have a method defined in a base class Animal that has a return type of type Animal:

Java Code:
public class Animal { 
   Animal createCreature() {
      // Code to create an Animal object and return a reference to it... 
   }

   // Rest of the class definition ...
}
You can redefine the createCreature() method in a derived class Cat like this:

Java Code:
public class Cat extends Animal { 
   @Override 
   Cat createCreature() {
      // Code to create a Cat object and return a reference to it... 
   }

   // Rest of the class definition...
}
As long as the return type for the method in the derived class is a subclass of the return type in the base class, as you have here, even though the return types are different you can still get polymorphic behavior. I can summarize the conditions that need to be met if you want to use polymorphism as follows:
  • The method call for a derived class object must be through a variable of a base class type.
  • The method called must be defined in the derived class.
  • The method called must also be declared as a member of the base class.
  • The method signatures for the method in the base and derived classes must be the same.
  • Either the method return type must be the same in the base and derived classes or the return types must be covariant.
  • The method access specifier must be no more restrictive in the derived class than in the base.


When you call a method using a variable of a base class type, with polymorphism you end up with a method that is called being selected based on the type of the object stored, not the type of the variable. Because a variable of a base type can store a reference to an object of any derived type, the kind of object stored is not known until the program executes. Therefore the choice of which method to execute has to be made dynamically when the program is running—it cannot be determined when the program is compiled. The bark() method that is called through the variable of type Cat in the earlier illustration may do different things depending on what kind of object the variable references. As you later see, this introduces a whole new level of capability in programming using objects. It implies that your programs can adapt at run time to accommodate and process different kinds of data quite automatically.

Note that polymorphism applies only to methods. It does not apply to data members. When you access a data member of a class object, the variable type always determines the class to which the data member belongs. This implies that a variable of type Cat can only be used to access data members of the Cat class. Even when it references an object of a derived type, Siamese, for example, you can only use it to access data members of the Cat part of a Siamese object.

Using Polymorphism

Note how polymorphism relies on the fact that you can assign an object of a subclass type to a variable that you have declared as being of a superclass type. If you declare the variable:

Java Code: Declare a variable of type Animal
Animal theAnimal = null;
Then you can make the Animal refer to an object of any of the subclasses of the class Animal. For example, to reference an object of type Cat, we do the following:

Java Code:
theAnimal = new Cat(“Charlie”);
You could also initialize the variable theAnimal to reference an object when you declare it:

Java Code:
Animal theAnimal = new Cat(“Charlie”);
This principle applies quite generally. You can use a variable of a base class type to store a reference to an object of any class type that you have derived, directly or indirectly, from the base. You can see what magic can be wrought with this in practice by extending the previous example. You can add a new method to the class Cat that displays the sound a Cat makes. You can add a couple of new subclasses that represent some other kinds of animals.

Working with Multiple Levels of Inheritance

As I indicated at the beginning of the chapter, there is nothing to prevent a derived class from being used as a base class. For example, you could derive a class Persian from the class Cat without any problem. If we start the Persian class off with minimal amount of code, we would have the following:

Java Code:
class Persian extends Cat { 
   public Persian(String aName) {
      super(aName, “Persian”);
   }
}
Now you can add this by adding a Persian object to the array theAnimals in the listing below:

Java Code: Animal Array Declaration
Animal[] theAnimals = {
				new Dog(“King”, “German Shepard”), 
				new Cat(“Max”, “Abyssinian”), 
				new Duck(“Daffy”,”Aylesbury”), 
				new Persian(“Felix”)
};
The class Persian inherits members from the class Cat, including the members of Cat that are inherited from the class Animal. The class Cat is a direct superclass, and the class Animal is an indirect superclass of the class Persian. The only additional member of Persian is the constructor. This calls the Cat class constructor using the keyword super and passes the value of aName and the String object “Persian” to it.

Summary

OK. We have covered the most of the key parts of inheritance including multiple inheritance. In the last article on Java Classes, we will look at abstract classes, the universal superclass and casting objects among other related topics. See you then.