Close
Close Window

MHC S25 COMSC 205: Data Structures

Chapter 4 Object Oriented Programming I: Inheritance

«  3.3. Variable Scoping   ::   Contents   ::   4.2. Java’s Inheritance Mechanism  »

4.1. Introduction to Inheritance

4.1.1. Class Hierarchy and Inheritance

How are classes related to each other? In Java, and in any other object-oriented language, classes are organized in a class hierarchy.

A class hierarchy is like an upside-down tree. At the very top of the hierarchy is the most general class. In Java, the most general class is the Object class. The classes below Object in the hierarchy are known as its subclasses. Since all of the objects we use in our programs belong to some class or other, this is like saying that every object is an Object.

The figure below illustrates the concept of a class hierarchy using some of the classes described in this section. Notice that the Object class occurs at the top of the hierarchy. It is the most general class. It has features that are common to all Java objects.

_images/jjj_classhier.png

As you move down the hierarchy, the classes become more and more specialized. An Account is an Object but it contains attributes – customerID and balance – that it more specialized than its parent class (Object).

Notice that we have added a Person class to the hierarchy as the superclass of Customer. Customers are more specialized than persons: they have bank accounts.

A subclass is said to inherit the attributes (variables) and actions (methods) of its superclass. Thus, a Customer would inherit things like a name, address, phone number and other attributes from the Person class. The subclass is said to extend the superclass by adding attributes and actions to those it inherits.

This class inheritance is similar to the classification of natural things. A horse is a mammal. Horses inherit the characteristic of being warm blooded by virtue of also being mammals. But they also have specialized attributes – manes, hooves – that distinguish them from other mammals, such as cows and humans.

4.1.2. java.lang.Object toString()

The most general class in Java’s class hierarchy is the java.lang.Object class. It is the superclass of all classes that occur in Java programs. By default, it is the direct superclass of any class that does not explicitly specify a pedigree in its class definition.

All subclasses of Object inherit the public and protected methods contained in Object, so all such methods can be thought of as belonging to the subclasses. This means that all classes inherit the methods of the Object class, because every class is a subclass of it. In this section, let’s look briefly at how we can use an inherited method and also at how we can override it–that is, redefine the method–if it doesn’t exactly suit our purposes.

One of the most useful methods in the Object class is the toString() method:

The toString() method returns a String representation of its object. For example, o1.toString() will return a String that in some sense describes o1.

Suppose we have the following class written:

 1 class Student {
 2   private String name;
 3   private String email;
 4   private int id;
 5
 6   public Student(String initName, String initEmail, int initId) {
 7      name = initName;
 8      email = initEmail;
 9      id = initId;
10   }
11}

Note

Remember that all Java classes are a subclass of Object!

Because Student is a subclass of Object, it inherits the toString() method. To illustrate the default behavior of toString(), let’s use it with a Student instance:

1Student stu = new Student("Mary Lyon", "mlyon22@mtholyoke.edu", 42);
2System.out.println(stu.toString());

This code segment creates one Student instance, named stu. The inherited toString() method is then invoked on the Student instance, which produces the following output:

Student@7ad041f3

What this experiment shows is that the default definition of toString() returns some kind of internal representation of its object. It looks as if it returns the name of the object’s class concatenated with its memory address. This may be useful for some applications. But for most objects we will want to override the default definition to make the toString() method return a string that is more appropriate for OneRowNim.

What String should the g1.toString() method return? Let’s have it return a String that reports the Student instances’s current state, which are the values stored in the two instance variables.

To override a method, you simply define a method with the same signature in the subclass. If you call toString() with an instance of the subclass, its version of the method will be used. In this way, the subclass method overrides the superclass version. Thus, Student.toString() will have the following signature:

public String toString()

Let us describe the state of a Student instance very briefly in the string returned by the toString() method:

public String toString() {
    return "Name: " + name + ", email: " + email + ", id: " + id;
}

If we add the previous toString() method to the Student class and then run the following main method:

1public static void main(String[] args) {
2    Student stu = new Student("Mary Lyon", "mlyon22@mtholyoke.edu", 42);
3    System.out.println(stu.toString());
4}

We get the following output:

Name: Mary Lyon, email: mlyon22@mtholyoke.edu, id:42

Since System.out.println looks for a String to print out, it will automatically look for a toString() method of an object and invoke it. It is possible to leave out the method call to toString() inside System.out.println methods.

1// Equivalent code
2System.out.println(stu.toString());
3System.out.println(stu);

While this new method may not play an important role in the Student class, it does provide a very brief, understandable description of the state of the object. This is the reason that the toString() method was included in the Object class.

4.1.3. Motivating Inheritance and Polymorphism

Among the most important concepts in object oriented programming are the concepts of inheritance and polymorphism. We first compared inheritance to the natural form of inheritance, in which horses and cows share certain inherited characteristics, such as being warm-blooded, by virtue of their being mammals.

We took a more technical look at inheritance above, where we talked about the toString() method and how it is inherited from the Object class. We illustrated there how subclasses of Object could override the inherited toString() method in order to customize it for their purposes. We also introduced the idea of polymorphism, in which a method call, such as obj.toString(), can have different behaviors depending on the type of object, obj, on which it is called.

In following sections we will take a much closer look at these important object-oriented concepts. We will learn how Java’s dynamic binding mechanism works and how it makes polymorphism possible. Most importantly, we will see why inheritance and polymorphism are important elements of object-oriented design.

   «  3.3. Variable Scoping   ::   Contents   ::   4.2. Java’s Inheritance Mechanism  »

Close Window