We communicate with objects using methods. Methods are executable code within each object, for which an interface has been established. Sometimes the interface is only for the object itself. Other times it is an interface accessible by other objects. This chapter discusses that topic in detail.
3.9 Object-Oriented Design: Inheritance and Polymorphism
This use of Object’s toString() method provides our first look at
Java’s inheritance mechanism and how it promotes the generality and
extensibility of the object-oriented approach. As a subclass of Object,
our OneRowNim class automatically inherits toString() and any other
public or protected methods defined in Object. We can simply use
these methods as is, insofar as they are useful to us. As we saw in this
case, the default version of toString() wasn’t very useful. In that case, we can override the method by defining a method in our class with the
exact same method signature. The new version of toString() can be
customized to do exactly what is most appropriate for the subclass.
One of the great benefits of the object-oriented approach is the ability
to define a task, such as toString(), at a very high level in the class
hierarchy and let the inheritance mechanism spread that task throughout the rest of the hierarchy. Because toString() is defined in Object,
you can invoke this method for any Java object. Moreover, if you override toString() in the classes you define, you will be contributing to its
usefulness. Two important lessons from this example are
Obviously there is much more that needs to be explained about Java’s
inheritance mechanism. Therefore, we will be revisiting this topic on
numerous occasions in subsequent chapters.
Another important concept of object-oriented design is polymorphism.
The toString() method is an example of a polymorphic method. The
term polymorphism is from the Greek terms poly, which means “many,”
and morph, which means “form.” The toString() method is polymorphic because it has different behavior when invoked on different objects.
For example, suppose we design a class, Student, as a subclass of
Object and define its toString() method to return the student ID
number. Given this design, then obj.toString() will return a student
ID if obj is an instance of Student, but if it is an instance of OneRowNim,
it will return the description of its state that we defined above. The
following code segment illustrates this point:
In this case, the variable obj is used to refer to a Student and then to a OneRowNim instance. This is okay because both classes are subclasses of Object. When toString() is invoked on obj, Java will figure out what subclass of Object the instance belongs to and invoke the appropriate toString() method.