IN THIS UNIT
Summary: In order to take advantage of everything an object-oriented language has to offer, you must learn about its ability to handle inheritance. This unit explains how superclasses and subclasses are related within a class hierarchy. It also explains what polymorphism is and how objects within a class hierarchy may act independently of each other.
Key Ideas
A class hierarchy describes the relationship between classes.
Inheritance allows objects to use features that are not defined in their own class.
A subclass extends a superclass (a child class extends a parent class).
Child classes do not have direct access to their parent’s private instance variables.
A child class can override the parent class methods by simply redefining the method.
Polymorphism is what happens when objects from child classes are allowed to act in a different way than objects from their parent classes.
The Object
class is the parent of all classes (the mother of all classes).
Sorry, this inheritance is not about a large sum of money that your crazy, rich uncle has left you. It is, however, a feature of Java that is immensely valuable. It allows objects from one class to inherit the features of another class.
One of the most powerful features of Java is the ability to create a class hierarchy. A hierarchy allows a class to inherit the attributes of another class, making the code reusable. This means that the classes on the lower end of the hierarchy inherit features (like methods and instance variables) without having to define them in their own class.
In biology, animals are ranked with classifications such as species, genus, family, class, kingdom, and so on. Any given rank inherits the traits and features from the rank above it.
Example
Demonstrate the hierarchy of cats, dogs, horses, and elephants. Note that all German shepherds are dogs, and all dogs are mammals, so all German shepherds are mammals.
So what does this have to do with computer programming? Well, in Java, a class has the ability to extend another class. That is, a child class (subclass) has the ability to extend a parent class (superclass). When a child class extends a parent class, it inherits the instance variables and methods of the parent class. This means that even though the child class doesn’t define these instance variables or methods on its own, it has them. This is a powerful way to reuse code without having to rewrite it.
Note: The methods from a parent class are inherited and can be used by the child class. However, the child class gets its own set of instance variables that are separate from the parent class. The instance variables for the parent and the instance variables for the child are two different sets of instance variables. The child class can only access the private instance variables of the parent by using the accessor and mutator methods from the parent class.
Something for Nothing
Child classes inherit the methods of their parent class. This means that the child objects automatically get these methods without having to define them for themselves.
extends
The words superclass and parent are interchangeable as are subclass and child. We say, “a child class extends a parent class” or “a subclass is derived from a superclass.” The phrase is-a refers to class hierarchy. So when we refer to classes such as Dog or Mammal, we say “a Dog is-a Mammal” or even “a GermanShepherd is-a Mammal.”
A class can extend at most one other class; however, there is no limit to how many classes can exist in a class hierarchy.
The Keyword extends
The keyword extends
is used to identify that inheritance is taking place. A child class can only extend one parent class.
Example
Simulate class hierarchy and inheritance using the Mammal hierarchy. Each subclass inherits the traits of its superclass and can add additional traits of its own.
Be Your Own Class
Child classes are allowed to define additional methods of their own. The total number of methods that the child class has is a combination of both the parent class and child class methods.
super
Constructors in a subclass are not inherited from their superclass. When you make an object from a child class, the child class constructor automatically calls the no-argument constructor of the parent class using the super() call (some integrated development environments, or IDEs, display this instruction). However, if you want to call a parent constructor with arguments from the child class constructor, you need to put that in your code explicitly as the first line of code in the child class constructor using the super(arguments) instruction. The child is then making a call to a parameterized constructor of the parent class. The actual parameters (arguments) passed in the call to the superclass constructor provide values that the constructor can use to initialize the object’s instance variables. Regardless of whether the superclass constructor is called implicitly or explicitly, the process of calling superclass constructors continues until the Object constructor is called. At this point, all of the constructors within the hierarchy execute beginning with the Object constructor.
Example
Demonstrate a child class that has two constructors. The no-parameter constructor makes a call to the parent’s no-parameter constructor. The parameterized constructor makes a call to the parent’s parameterized constructor. Note: The super() call must be the first line of code in each of the child’s constructors.
A subclass can only access or modify the private instance variables of its parent class by using the accessor and modifier methods of the parent class.
Children Don’t Have Direct Access to Their Parent’s private
Instance Variables
Parent and child classes may both contain instance variables. These instance variables should be declared private. This is data encapsulation. Children have to use the accessor and modifier methods of the parent class to access their parent’s private instance variables.
“Sometimes children want to act in a different way from their parents.”
In Java, a child class is allowed to override a method of a parent class. This means that even though the child inherited a certain way to do something from its parent, it can do it in a different way if it wants to. This is an example of polymorphism.
The way to make a child override a parent method is to redefine a method (the signature must be exactly the same) and change what is done in the method. When an object from the child class calls the method, it will perform the action that is found in the child class rather than the method of the parent class.
Example
All objects from the FamilyMember
class drink from a cup and eat with a fork. However, objects from the Baby
class drink from a cup and eat with their hands. All objects from the SporkUser
class drink from a cup and eat with a spork. In this case, the eat method of the FamilyMember
class is overridden by both the Baby
class and the SporkUser
class. Therefore, even though the name of the method is the same, the objects from Baby
class and SporkUser
class eat in a different way than objects from the FamilyMember
class. The decision of when to use the overridden method by all objects that extend a superclass is made when the program is compiled and this process is called static binding.
Any method that is called must be defined within its own class or its superclass. A subclass is usually designed to have modified (overridden) or additional methods or instance variables. A subclass will inherit all public methods from the superclass; these methods remain public in the subclass.
Polymorphism
Java uses the term polymorphism to describe how different child classes of the same parent class can act differently. This is accomplished by having the child class override the methods of the parent class.
A problem arises when we want to make a list of family members. To make an array or ArrayList
of people in the family, they all have to be of the same type! To solve this problem, we make the reference variables all of the parent type.
Example
Create a FamilyMember ArrayList
to demonstrate dynamic binding. Make the reference variables all the same type (the name of the parent class) and make the objects from the child classes. Allow each object to eat and drink the way they were designed to eat and drink. The decision of how each FamilyMember
object eats is decided while the program is running (known as run-time) and this process is called dynamic binding. It’s pretty cool!
Reference Variables and Hierarchy
The reference variable can be the parent of a child object.
The reference variable cannot be a child of a parent object.
super
from a Child MethodEven if a child class overrides a method from the parent class, an object from a child class can call its parent’s method if it wants to; however, it must do it from the overriding method and pass the appropriate parameters. By using the keyword super, a child can make a call to the parent method that it has already overridden. We say, “The child can invoke the parent’s method if it wants to.”
Example
Revise the Baby class so that if a baby is older than three years, it eats with either its hands or a fork; otherwise it eats with its hands. Use the keyword super to make a call to the parent’s eat method. Also, add an instance variable for the age.
A child object has the ability to perform all the public methods of its parent class. However, a parent does not have the ability to do what the child does if the child action is original. Also, if a child object has a parent reference variable, the child does not have the ability to perform any of the unique methods that are defined in its own class.
Example
Demonstrate that a parent reference variable cannot perform any of the methods that are unique to a child class. A FamilyMember
object does not know how to throwTantrum. Only a Baby
object knows how to throwTantrum. Note: Even though babyCousin
is a Baby
object, the FamilyMember
reference variable prevents it from being able to throwTantrum.
The problem described in the previous example can be solved using a technique called downcasting. This is similar to—but not exactly the same as—casting an int
to a double
. A parent object reference variable is cast to the object type of the object that it references.
Downcasting
You can downcast a parent reference variable to a child object as long as the object it is referring to is that child.
Example 1
Demonstrate downcasting by allowing the parent reference variable to perform a method that is unique to a child class. The parent reference variable is cast as a child and must refer to the child object. Pay close attention to the parentheses when casting.
Example 2
You are not allowed to cast a parent reference object to a child if the object is a parent. In this example, mom is a FamilyMember
reference variable that refers to a FamilyMember
object. Attempting to cast mom as a Baby
results in an error.
Object
ClassThe Object class is the mother of all classes. It is part of the java.lang
package. Every class, even the ones you write, is a descendent of the Object class. The extends is implied, so you don’t have to write, “extends Object”, in your own classes. The Object class does not have any instance variables, but it does have several methods that every descendent inherits. Two of these methods, the toString and the equals, are tested on the AP Computer Science A Exam and are included on the Java Quick Reference sheet. Subclasses of Object
often override the equals
and toString
methods with class-specific implementation. You must be able to implement the toString
method; however, you only need to know how to use the equals method (like we do when we compare String
objects).
toString
MethodThe toString method is inherited from the Object class and was created to describe the object in some way, typically by referencing its instance variables. The Object class’s toString
method doesn’t give you anything valuable (it returns the hex value of the object’s address). Most of the time, when creating your own classes, you will override the toString
method so it returns a String that describes the object in a meaningful way.
Example
Override the toString
method for the Circle class (used in Unit 5) so the method gives a description of the Circle object that calls it. The String that is returned should include the radius of the circle.
Overriding the toString
Method All classes extend the Object class. When you design your own classes, be sure to override the toString() method of the Object class so that it describes objects from your class in a unique way using its own instance variables.
Object
If a method’s parameter list contains an Object
reference variable, then you will have to downcast the reference before using it. You must make sure that the object that you are casting is-a
object from the class.
Example
Demonstrate how to handle an Object
reference parameter. In this example, when the FamilyMember
object, uncleDon
, gets passed to the timeToEat
method, he is sent as a FamilyMember
reference variable. When he is received by the timeToEat
method, he is renamed as hungryMember
and is now an Object
reference. Finally, he is cast to a FamilyMember
and is then able to eat.
• One major advantage of an object-oriented language is the ability to create a hierarchy of classes that allows objects from one class to inherit the features from another class.
• A class hierarchy is formed when one class extends another class.
• A class that extends another class is called the child or subclass.
• The class that is extended is called the parent or superclass.
• A class can only extend one other class.
• A class hierarchy can extend as many times as you want. That is, a child can extend a parent, then the parent can extend another parent, and so on.
• When a class hierarchy gets extended to more than just one parent and one child, the lower ends of the hierarchy inherit the features of each of the parent classes above it.
• The phrase “is-a” helps describe what parent classes a child class belongs to.
• If you want a child class to modify a parent class’s method, then you override the parent class’s method. To do this, you simply redefine the method in the child class (using the exact same method declaration and replace the code with what you want the child to do).
• The word “super” can be used to refer to either a parent’s constructor or methods.
• To purposefully call the no-argument super constructor, you must put super() as the first line of code in the child’s constructor. Other instructions are placed after the super() call.
• To call the parameterized super constructor, you must put super(arguments) as the first line of code in the child’s parameterized constructor. Other instructions are placed after the super() call.
• If you write a method that overrides the parent class’s method, you can still call the original parent’s method if you want to. Example: super.parentMethod()
.
• A reference variable can be a parent class type if the object being created is its child class type.
• A reference variable cannot be a child class type if the object being created is its parent class type.
• A reference variable that is of a parent data type can be cast to a child data type as long as the object that it is referencing is a child object of that type.
• Polymorphism is when more than one child class extends the same parent class and each child object is allowed to act in a different way than its parent and even its siblings.
• If several child classes extend the same parent class and each child class overrides the same method of the parent class in its own unique way, then each child will act differently for that method.
• Static binding is the process of deciding which method the child reference variable will perform during compile-time.
• Dynamic binding is the process of deciding which method the parent reference will perform during run-time.
• The Object
class is the mother of all classes in Java since it is the root of the class hierarchy and every class has Object
as a superclass.
• The Object class contains two methods that are tested on the AP exam: equals and toString.
• The public boolean equals(Object other)
method returns true if the object reference variable that calls it is referencing the same exact object as other. It returns false if the object reference variables are not referencing the same object.
• It is common to override the equals
method when you want to determine if two objects from a class are the same.
• The public String toString()
method returns a String representation of the object.
• It is very common to override the toString()
method when generating your own classes.
• Downcasting is casting a reference variable of a parent class to one of its child classes.
• Downcasting is commonly used when an Object
is in a parameter list or ArrayList
.
• A major problem with downcasting is that the compiler will not catch any errors, and if the cast is made incorrectly, a run-time error will be thrown.
1. Assuming all classes are defined in a manner appropriate to their names, which of the following statements will cause a compile-time error?
(A) Object obj = new Lunch();
(B) Lunch lunch = new Lunch();
(C) Lunch sandwich = new Sandwich();
(D) Lunch lunch = new Object();
(E) Sandwich sandwich = new Sandwich();
Questions 2–4 refer to the following classes.
2. Which of the following is true with respect to the classes defined above?
I. Freshman
is a subclass of UnderClassman
and UnderClassman
is a subclass of Student
II. Student
is a superclass of both UnderClassman
and Freshman
III. UnderClassman
is a superclass of Freshman
and a subclass of Student
(A) I only
(B) II only
(C) I and II only
(D) II and III only
(E) I, II, and III
3. Which of the following lists of instance data contains only variables that are directly accessible to a Freshman
class object?
(A) middleSchoolCode
(B) gradYear
, gpa
(C) homeRoomNum
, counselor
(D) middleSchoolCode
, homeRoomNum
, counselor
(E) middleSchoolCode, homeRoomNum, counselor, gradYear, gpa
4. Assume that all three classes contain parameterized constructors with the following declarations and that all variables are logically named.
Which of the following calls to super
would appear in the constructor for the Freshman
class?
(A) super(gradYear, gpa, homeRoomNum, counselor, middleSchoolCode);
(B) super(gradYear, gpa, homeRoomNum, counselor);
(C) super(homeRoomNum, counselor);
(D) super(gradYear, gpa);
(E) super();
5. Consider the following method in the Student
class.
A Freshman
object must attendClass
like a Student
object, but also have the teacher initial his/her homework planner (using the initialPlanner
method, not shown).
Which of the following shows a possible implementation of the Freshman
attendClass
method?
(A)
(B)
(C)
(D)
(E)
Questions 6–7 refer to the following classes.
Assume ArrayList<String> members_1
and ArrayList<String> members_2
have been properly instantiated and initialized with a non-zero number of appropriate elements.
6. Which of the following declarations is NOT valid?
(A)
(B)
(C)
(D)
(E) All of the above are valid.
7. Which of the following could replace /* missing code */
in the SchoolClub
constructor to ensure that all instance variables are initialized correctly?
(A)
(B)
(C)
(D)
(E)
Questions 8–9 refer to the following classes.
8. Consider the following code segment.
What is printed as a result of executing the code segment?
(A) contains kazoo
(B) kazoo
(C) contains kazoo for a child age 4
(D) Nothing is printed. Compile-time error: illegal cast
(E) Nothing is printed. Run-time error: illegal cast
9. Consider the following code segment.
What is printed as a result of executing the code segment?
(A) contains blocks
(B) contains blocks for a child age 4
(C) contains kazoo for a child age 4
(D) Nothing is printed. Compile-time error: there is no setContents
method in the KidsPresent
class
(E) Nothing is printed. Run-time error: there is no setContents
method in the KidsPresent
class
10. Free-Response Practice: Point3D Class
Consider the following class:
Write the class Point3D
that extends this class to represent a three-dimensional point with x, y, and z coordinates. Be sure to use appropriate inheritance. Do not duplicate code.
You will need to write:
a. A constructor that takes three int
values representing the x, y, and z coordinates
b. Appropriate mutator and accessor methods (setters and getters)
Bullets mark each step in the process of arriving at the correct solution.
1. The answer is D.
• When you instantiate an object, you tell the compiler what type it is (left side of the equal sign) and then you call the constructor for a specific type (right side of the equal sign). Here’s where you can put is-a
to good use. You can construct an object as long as it is-a
version of the type you have declared. You can say, “Make me a sandwich, and I’ll say thanks for lunch,” and you will always be right, but you can’t say, “Make me lunch and I’ll say thanks for the sandwich.” What if I made soup?
• Option A is correct, since Lunch is-a Object.
• Options B and E are correct since Lunch is-a Lunch, and Sandwich is-a Sandwich. (Don’t confuse the variable name sandwich with the type Lunch. It’s a bad programming choice, since a reader expects that a variable named sandwich is an object of the class Sandwich, but it’s legal.)
• Option C is correct since Sandwich is-a Lunch.
• Option D is incorrect. Object is not a Lunch. It’s not reversible. The one on the right has to have an is-a relationship to the one on the left in that order. Option D will not compile.
2. The answer is E.
• Superclass refers to grandparents as well as parents, all the way up the inheritance line, and subclass refers to grandchildren as well as children, all the way down the inheritance line, so all three relationships are true.
3. The answer is A.
• A Freshman
object will have direct access to its own private variables.
• The instance variables for UnderClassman
and Student
are private and can only be accessed within that class.
• Please note that it is considered a violation of encapsulation to declare instance variables public, and points may be taken off on the AP exam if you do so!
4. The answer is B.
• Since the super call must be the first thing in the constructor, the Freshman constructor will hang on to the parameter middleSchoolCode
and use the super call to pass the remaining parameters to the constructor for Underclassman. It will then set its own instance variable to the middleSchoolCode
parameter. (It’s worth noting that the Underclassman constructor will set its own two variables and pass the remaining variables to its super constructor.)
5. The answer is D.
• Options A and B are incorrect. They show an incorrect usage of "extends". The keyword extends
belongs on the class declaration, not the method declaration.
• Option C is incorrect. It puts data types next to the arguments (actual parameters) in the super
method call. Types only appear next to the formal parameters in the method declaration.
• Option D is correct. It has fixed both of the above errors. The method with the same name in the superclass is called using the super.methodName
notation, and it is passed the two parameters it is expecting. Then the initialPlanner
method is called.
• Option E is incorrect. It attempts to assign the parameters directly to their corresponding variables in the Student class. The variables in the parent class should be private, so the child doesn’t know if they exist, and can’t access them even if they do. Also, the child class shouldn’t assume that assigning variables is all the parent class method does. Surely attendClass
involves more than that!
6. The answer is C.
• Option A is valid. It instantiates an array of Club
objects. The right side of the instantiation specifies that there will be two entries, but it does not instantiate those entries. This is a valid statement, but note that the entries in this array are null.
• Option B is valid. It uses an initialization list to instantiate the array of Club
objects. Club
has overloaded constructors. There is a constructor that takes an ArrayList<String>
as an argument, so the first entry is correct, and there is a no-argument constructor, so the second entry is correct.
• Option C is not valid. It uses an initialization list to instantiate an array of SchoolClub
objects, but the list includes not only a SchoolClub
object, but also a Club
object. We could make a Club[]
and include SchoolClub
objects, but not the other way around. Remember the is-a designation. A Club
is not a SchoolClub
.
• Option D is valid. It instantiates an array of SchoolClub
objects by giving an initialization list of correctly instantiated SchoolClub
objects.
7. The answer is A.
• The first statement in the constructor of an extended class is a super call to the constructor of the parent class. This may be an implicit call to the no-argument constructor (not explicitly written by you) or it may be an explicit call to any of the superclass’s constructors.
• Option B is incorrect. It calls the super constructor but passes a parameter of the wrong type.
• Option C is incorrect. this.SchoolClub
has no meaning.
• Option D is incorrect. This option is syntactically correct. The no-argument constructor will be called implicitly, but the members ArrayList
instance variable will not be set.
• Option E is incorrect. The super call must be the first statement in the constructor.
8. The answer is C.
• First of all, remember that when an object is printed, Java looks for that object’s toString
method to find out how to print the object. (If there is no toString
method, the memory address of the object is printed, which is not what you want!)
• Variable p is of type Present. That’s what the compiler knows. But when we instantiate variable p, we make is a KidsPresent. That’s what the runtime environment knows. So when the runtime environment looks for a toString method, it looks in the KidsPresent class. The KidsPresent toString prints both the contents and the appropriate age.
9. The answer is B.
• Since p is declared as a Present, and the Present class has a setContents
method, the compiler is fine with this sequence.
• When setContents
is called, the run-time environment will look first in the KidsPresent class and it will not find a setContents
method. But it doesn’t give up! Next it looks in the parent class, which is Present and there it is. So the run-time environment happily uses the Present class’s setContents
method and successfully sets the Present class’s contents variable to "blocks".
• When the KidsPresent toString
is called, the first thing it does is call super.toString()
, which accesses the value of the contents variable. Since that variable now equals "blocks", the code segment works as you might hope it would and prints "contains blocks for a child age 4".
10. On the AP exam, you are often asked to extend a class, as you were in this question. Check your answer against my version below. A few things to notice:
• The constructor takes x, y, and z but then immediately passes x and y to the Point class constructor through the super(x, y) call.
• x and y, their setters and getters are in the Point class; they don’t need to be duplicated here. Only variable z, setZ and getZ need to be added.