9.7. Object Superclass¶
The Object
class is the superclass of all other classes in Java and a part
of the built-in java.lang
package. If a parent class isn’t specified using
the extends
keyword, the class will inherit from the Object
class. What
does a class inherit from the Object
class? The AP CSA Java Quick Reference Sheet
lists the two main methods that are most frequently used:
String toString()
boolean equals(Object other)
9.7.1. toString()
method¶
One commonly overridden Object
method is toString()
, which is often used
to print out the attributes of an object. It is a good idea to write your own
toString()
method in every class. In a subclass, toString()
can call the
superclass toString()
method using super.toString()
and then add on its
own attributes.
In the following code, the Person
class overrides the toString
method
from Object
method and the Student
class then overrides it again. In
each class the new toString
method adds the new attributes from that class.
After trying the code below, complete the subclass called APStudent
that
extends Student
with a new attribute called APscore
and override the
toString()
method to call the superclass method and then add on the
APscore
. Uncomment the APStudent
object in the main method to test it.
9.7.2. equals
Method¶
One of the important methods inherited from Object
is the equals(Object
obj)
method. This method is used to test if the current object and the passed
object called obj
are equal. But what does that mean?
As you can see if you run the code below, the equals
method inherited from
Object
only returns true
if the two objects references refer to the same
object. In other words it is does the same test as ==
.
Try to guess what this code will print out before running it.
9.7.3. Overriding the equals
Method¶
The equals
method defined in Object
and thus inherited by all classes
only considers two object references equivalent if they refer to exactly the
same object. But we saw in Unit 2 that the String
class provides an
equals
method that considers two String
objects equivalent if they have
the same characters in the same order, even if they are actually different
objects. How does that work?
It is because the String
class has overridden the equals
method it
inherited from Object
to provide a definition of equality that makes more
sense.
As we saw in section 9.3 a class can override inherited methods by providing a
method with the same method signature (method name, parameter types, and return
type). String
has done that with equals
so when we compare String
objects with equals
that new method will be called instead of the inherited
one.
Try to guess what this code will print out before running it.
However, overriding equals
is a bit more involved than overriding
toString
. While the toString
method is only required to produce a
reasonable human-readable String
representation of an object, equals
has
to meet a more complex set of requirements in order to be useful.
You will not be expected to write your own equals
method on the AP exam but
it’s worth looking at what those requirements are and how to satisify them.
There are five requirements described in the Javadocs for equals
in
Object
that a properly implemented equals
must satisfy:
Equality is reflexive, meaning an object will be
equals
to itself:o.equals(o)
istrue
.Equality is symmetric:
o1.equals(o2)
returns the same value aso2.equals(o1)
.Equality is transitive: if
o1.equals(o2)
ando2.equals(o3)
theno1.equals(o3)
.Equality is consistent:
o1.equals(o2)
always returns the same value assuming the objects are not modified.No object is equal to
null
:o.equals(null)
is alwaysfalse
.
The other way to look at these requirements is as guarantees that are made to
you as a user of equals
. If you look at it that way, these requirements are
quite nice. Imagine how much harder it would be to use the String
equals
method if you couldn’t rely on the fact that s1.equals(s2)
is necessarily
the same as s2.equals(s1)
!
So even though the Java compiler can’t force you to implement equals
correctly, if you ever do want to override it, it’s important that you do. Let’s
look at what’s involved.
We’ll write a class Word
which represents a word in a particular language.
We want two Word
objects to be considered equals
if and only if they are
spelled the same and come from the same language. The latter requirement is
because sometimes different languages have words that are spelled the same but
with different meanings such as “pie” which in English is a tasty baked treat
and in Spanish is what we call a “foot” in English.
Try to guess what this code will print out before running it. Click on the CodeLens button to step forward through the code and watch the memory.
The basic recipe for writing your own equals method, is:
Use the
public boolean equals(Object other)
method signature. Make sure the parameter type isObject
, not the class you are defining.Check of
this == other
to quickly returntrue
when comparing an object to itself.Use
instanceof
to check if other is an instance of this class and returnfalse
if not.Cast
other
to the current class.Finally compare this object’s attributes to the other object’s with
==
for primitive types likeint
anddouble
andequals
for reference types. If you need to compare multiple attributes&&
together the comparisons of the individual attributes since two objects should only be equal if all the attributes match.
Note that the requirements on equals
make it almost impossible to correctly
override it in a subclass of a class that has already overridden the Object
version. To see why, imagine if we made a subclass of Word
,
ClassifiedWord
and added another attribute, partOfSpeech
.
If we override equals
in the ClassifiedWord
to only consider two
ClassifiedWord
objects equals
if their spelling, language, and part of
speech match, that will break the symmetry since
regularWord.equals(classifiedWord)
will invoke the equals
from Word
which will only compare the spelling and language of the word but
classifiedWord.equals(regularWord)
will return false
assuming the
equals
in ClassifiedWord
checks that other
is an instanceof
ClassifiedWord
. In general you should only provide an overridden equals
method in one class in a class hierarchy.
9.7.4. Programming Challenge : Savings Account¶
The following code contains the beginning of a class for representing a bank account containing the account holder’s name and the money balance in the account.
Work in pairs to write the following code and test each part before moving on to the next step:
Implement a
toString
method inAccount
that returns aString
representing the instance variables inAccount
in the form name, comma, space, balance.Write a subclass called
SavingsAccount
that extendsAccount
and adds an interest rate variable.Write a constructor with 3 arguments (name, balance, interest rate) for the
SavingsAccount
class that uses the super constructor.Write a
toString
method forSavingsAccount
that returns a string consisting of the result of the superclass’stoString
plus a comma, a space, and the interest rate.
Complete the subclass SavingsAccount
below which inherits from
Account
and adds an interest rate variable. Write a constructor with 3
arguments, a toString
, and an equals
method for it. Uncomment the
code in main
to test your new class and methods.
9.7.5. Summary¶
The
Object
class is the superclass of all other classes in Java and a part of the built-injava.lang
package.The following
Object
class methods are part of the Java Quick Reference:String toString()
boolean equals(Object other)
Subclasses of Object often override the
toString
andequals
methods with class-specific implementations.When overriding
equals
, it’s important to satisfy all the requirements of a correct implementation.