Week4

Class Hierarchies

Inheritance from the Object class

Classes are used to clarify the concepts of the problem domain in object-oriented programming. Every class we create adds functionality to the programming language. This functionality is needed to solve the problems that we encounter. An essential idea behind object-oriented programming is that solutions rise from the interactions between objects which are created from classes. An object in object-oriented programming is an independent unit that has a state, which can be modified by using the methods that the object provides. Objects are used in cooperation; each has its own area of responsibility. For instance, our user interface classes have so far made use of Scanner objects.

Every Java class extends the class Object, which means that every class we create has at its disposal all the methods defined in the Object class. If we want to change how these methods are defined in Object function, they must be overriden by defining a new implementation for them in the newly created class. The objects we create receive the methods equals and hashCode, among others, from the Object class.

Every class derives from Object, but it's also possible to derive from other classes. When we examine the API (Application Programming Interface) of Java's ArrayList, we notice that ArrayList has the superclass AbstractList. AbstractList, in turn, has the class Object as its superclass.


  java.lang.Object
  java.util.AbstractCollection<E>
    java.util.AbstractList<E>
       java.util.ArrayList<E>

Each class can directly extend only one class. However, a class indirectly inherits all the properties of the classes it extends. So the ArrayList class derives from the class AbstractList, and indirectly derives from the classes AbstractCollection and Object. So ArrayList has at its disposal all the variables and methods of the classes AbstractList, AbstractCollection, and Object.

You use the keyword extends to inherit the properties of a class. The class that receives the properties is called the subclass, and the class whose properties are inherited is called the superclass.

We've encountered situations where reference-type variables have other types besides their own one. For example, all objects are of type Object, i.e., any given object can be represented as a Object-type variable in addition to its own type.

String text = "text";
Object textString = "another string";
String text = "text";
Object textString = text;

In the examples above, a string variable is represented as both a String type and an Object type. Also, a String-type variable is assigned to an Object-type variable. However, assignment in the other direction, i.e., setting an Object-type variable to a String type, will not work. This is because Object-type variables are not of type String.

Object textString = "another string";
String text = textString; // WON'T WORK!

What is this all about?

In addition to each variable's original type, each variable can also be represented by the types of interfaces it implements and classes that it inherits. The String class inherits the Object class and, as such, String objects are always of type Object. The Object class does not inherit a String class, so Object-type variables are not automatically of type String. Take a closer look at the String API documentation, in particular at the top of the HTML page.
A screenshot of the String Class API documentation. The screenshot shows that the String class inherits the class Object.

The API documentation for the String class begins with a generic header followed by the class' package (java.lang). After the package details, the name of the class (Class String) is followed by the inheritance hierarchy of the class.

  java.lang.Object
   java.lang.String

The inheritance hierarchy lists all the classes that the given class has inherited. Inherited classes are listed in the order of inheritance, with the class being inspected always at the bottom. In the inheritance hierarchy of the String class, we see that the String class inherits the Object class. In Java, each class can inherit one class at most. On the other hand, the inherited class may have inherited another class. As such, a class may indirectly inherit more than a single class.

The inheritance hierarchy can also be thought of as a list of the different types that the class implements.

Knowledge of the fact that objects can be of many different types — of type Object, for instance — makes programming simpler. If we only need methods defined in the Object class, such as toString, equals and hashCode in a method, we can simply use Object as the type of the method parameter. In that case, you can pass the method for any object as a parameter. Let's take a look at this with the printManyTimes method. The method gets an Object-type variable and the number of print operations as its parameters.

public class Printer {
    public void printManyTimes(Object object, int times) {
        for (int i=0; i < times; i++) {
            System.out.println(object.toString());
            // or System.out.println(object);
        }
    }
}

The method can be given any type of object as a parameter. Within the printManyTimes method, the object only has access to the methods defined in the Object class because the object is known in the method to be of type Object. The object may, in fact, be of another type.

Printer printer = new Printer();

String string = " o ";
List<String> words = new ArrayList<>();
words.add("polymorphism");
words.add("inheritance");
words.add("encapsulation");
words.add("abstraction");

printer.printManyTimes(string, 2);
printer.printManyTimes(words, 3);
Sample output

o o [polymorphism, inheritance, encapsulation, abstraction] [polymorphism, inheritance, encapsulation, abstraction] [polymorphism, inheritance, encapsulation, abstraction]

Let's continue to look at the API description of the String class. The inheritance hierarchy in the description is followed by a list of interfaces implemented by the class.

  All Implemented Interfaces:
  Serializable, CharSequence, Comparable<String>

The String class implements the Serializable, CharSequence, and Comparable interfaces. An interface is also a type. According to the class' API description, the following interfaces can be set as the type of a String object.

Serializable serializableString = "some text";
CharSequence charSequenceString = "more text";
Comparable<String> comparableString = "other text";

Note that we only discuss the Comparable interface in a later week, and the Serializable and CharSequence interface are only used as an example, but are not interfaces you have to be familiar with.

Since we're able to define the type of a method's parameter, we can declare methods that receive an object that implements a specific interface. When a method's parameter is an interface, any object that implements that interface can be passed to it as an argument.

We'll extend the Printer class so that it has a method for printing the characters of objects that implement the CharSequence interface. The CharSequence interface provides, among other things, methods int length() for getting a string's length and char charAt(int index), which retrieves a character from a given index.

public class Printer {
    public void printManyTimes(Object object, int times) {
        for (int i=0; i < times; i++) {
            System.out.println(object.toString());
            // or System.out.println(object);
        }
    }

    public void printCharacters(CharSequence charSequence) {
        for (int i=0; i < charSequence.length(); i++) {
            System.out.println(charSequence.charAt(i));
        }
    }
}

The printCharacters method can be passed any object that implements the CharSequence interface. These include String as well as StringBuilder, which is often more efficient for building String objects step by step than using the + operator to repeatedly concatenate String objects. The printCharacters method prints each character of a given object on its own line.

Printer printer = new Printer();

String string = "works";

printer.printCharacters(string);
Sample output

w o r k s

Exercise

Test your knowledge

In this quiz, you can test your knowledge on the subjects covered in this chapter.

Suppose we create an object with the expression new ArrayList<Integer>. For each of the following types, determine if this object has that type:

  • Object
  • Integer
  • List<Integer>
  • String
  • Integer []

What is special about the Object class? How does it relate to class hierarchies?


Although we do not work with them, Java has various classes that can be used to build visual user interfaces with buttons, windows and textfields. One class that can be used for this is the JTextField class. Search for the Javadoc page of JTextField and determine which super classes JTextField has in it's class hierarchy. How many interfaces are implemented by JTextField?

Note: you do not have to understand what a JTextField does or how you to use it to answer this question.

You have reached the end of this section! Continue to the next section: