Welcome! This guide will teach you everything you need to know about Unit 9 for the AP CSA exam. This unit is weighed 5-10% on the exam.
Quick Note
Throughout this guide, I use the this
keyword. This simply refers to the current object your referring to. If we had the following constructor for something like an Animal
class that has a String
attribute of type:
public Animal(String t) {
type = t;
}
The following would constitute as the same code as well:
public Animal(String type) {
this.type = type;
}
The this
keyword is used to distinguish between the method argument and the class attribute. The this
keyword doesn't show up on the AP exam, but they won't take off points if you use it an FRQ.
9.1 - Create Superclasses and Subclasses
Introduction
When one thinks of inheritance, they may think of biological traits passed down from parent to child.
In Java, inheritance is used to build a hierarchy of classes that have similar traits. Parent classes (aka Superclasses) have atrributes and methods that can be inherited by child classes (aka Subclasses)
In Java, each subclass can only have one superclass.
Practice Question
Scroll below answer choices to see the answer
In a particular school system, there will be two types of people: students and teachers. Both types of people will have names, ages, addresses, and ID numbers. Students will also have a grade level and GPA, while teachers of a hire date and a salary.
Which of the following would be the best class design for this scenario?
A. Three independent, unrelated classes: Person
, Student
, and Teacher
B. A Person
superclass, and two subclasses: Student
and Teacher
C. A Person
superclass. Teacher
is a subclass of Student
, and Student
is a subclass of Teacher
.
D. A Student
superclass. Teacher
is a subclass of Student
, and Student
is a subclass of Person
.
E. Two superclasses, Student
, and Teacher
, with Person
as a subclass of each
The answer would be B because the best choice for a superclass would be Person
. Both Student
and Teacher
have names, ages, etc.; it would be best to put those atributes in a generic superclass, like Person
, that can be further extended by subclasses, like Student
and Teacher
.
Extending Superclasses
The keyword extends is used to create an inheritance relationship between a superclass and a subclass. For example, if we have the following UML diagram (not heavily tested on AP Exam)
We can see that Rectangle
and Circle
are both subclasses of GeometricObject
. To write this as code, we would write
public class Rectangle extends GeometricObject {
// ...
}
public class Circle extends GeometricObject {
// ...
}
What would not be a valid statement would be something such as
public class Rectangle extends Circle {}
public class GeometricObject extends Rectangle {}
Anwyays, Rectangle
and Circle
not only have access to their class specific methods, but they also have all the public methods from their superclass, GeometricObject
. Take a look at the folliwng method calls.
GeometricObject geoObject = new GeometricObject();
Circle circle = new Circle(4);
Rectangle rectangle = new Rectangle(3, 5);
circle.getColor(); // Valid ✅ From superclass
circle.getDiameter(); // Valid ✅
rectangle.getDateCreated(); // Valid ✅ From superclass
rectangle.setWidth(6); // Valid ✅
geoObject.setColor("red"); // Valid ✅
geoObject.getRadius(); // Invalid ❌, this is a method from Circle and not GeometricObject
circle.getWidth(); // Invalid ❌, this is a method from Rectangle and not Circle
9.2 - Creating Constructors for Subclasses
The following class hierarchy diagram will be used for this section as a demonstration. It was taken from AP Classroom.
Subclass Constructors
Lets do a partial implementation of the Performer
class:
public class Performer {
private String name;
private int age;
public Performer() {
name = "John";
age = 30;
}
public Performer(String name, int age) {
this.name = name;
this.age = age;
}
// ...
}
Constructos are not inherited from superclasses. By default, every time you instantiate an object, the no-arg constructor of the object's superclass will be invoked.
For example, if we implement the Musician
class:
public class Musician extends Performer {
private String instrument;
public Performer() {
instrument = "Piano";
}
public Performer(String instrument) {
this.instrument = instrument;
}
public String getInstrument() { return instrument; }
public void playInstrument() {
// ...
}
}
If we create an object using the Musician
class, the no-arg Performer
constructor will be invoked, and then the Musician
constructor will be invoked.
Musician musician = new Musician("Guitar"); // Name -> John, Age -> 30, Instrument -> Guitar
Using the super
keyword to invoke constructors
The keyword super
refers to the superclass of an object and can be used to invoke an object's superclass's methods and constructors. Invoking methods using super
is discussed in topic 9.4.
The syntax for calling the constructor of a superclass is:
public class A extends B {
public A() {
super(); // can also pass in parameters if needed
}
}
When we said that an object's superclass constructor is automatically invoked, it really meant that Java would automatically insert super();
before all of the subclass constructor logic.
If you want to call super
, it must be the FIRST statement in the constructor.
If we go back to the Musician
and Performer
classes, if we wanted to add a constructor that allows you to give the Musician a name and an age as well, you would have to call super
with the name and age as parameters.
public class Musician {
// ... previously defined logic above
public Musician(String name, int age, String instrument) {
super(name, age);
this.instrument = instrument;
}
}
9.3 - Overriding Methods
This is a short and sweet topic, but it has a very important concept.
When writing methods for a subclass, you can do one of the following
- Inherit public methods from the superclass
- Write new methods in subclass
- Override (aka write new implmentation) of a method that is already in the superclass
For example if the Peformer
class had a method called perform
, any subclass of Performer
can write a new implementation for that same method. Lets do it with the Musician
class:
public class Musician {
// ... previous logic
@Override
public void perform() {
System.out.println("Musician performs " + instrument);
}
}
As you can see, it is generally a good idea to add the @Override
annotation to let other developers know that this is an overrided method. This won't be on the AP Exam because they want to test your knowledge on this.
9.4 - Using super
to invoke methods
This is pretty self-explantory. You can use super
to call a superclass's methods by saying:
super.getName();
super.setAge(76);
It doesn't have to be the first statement in the method.
Practice Question 9.4.1
Scroll below answer choices to see the answer
Consider the following classes:
public class Device {
private String name;
private String model;
public Stadium(String n, String m) {
name = n;
model = m;
}
public void printInfo() {
System.out.print("Device with name: " + name + " and model: " + model);
}
}
public class Laptop extends Device {
private String os;
public Laptop(String n, String m, String o) {
super(n, m);
os = o;
}
public void printInfo() {
/* Missing Code */
}
}
The following code segment appears in a class other than Laptop
or Device
:
Laptop laptop = new Laptop("MacBook", "Pro", "macOS");
The goal is to produce the following output:
MacBook that is the model Pro - runs macOS
Which of the following can be used to replace /* missing code */
?
A:
System.out.print(name + " that is the model " + model + " - runs " + os)
B:
super();
System.out.print("- runs " + os)
C:
super.prinfInfo();
System.out.print("- runs " + os)
D:
super.prinfInfo("- runs " + os);
Practice Question 9.4.2
Scroll below answer choices to see the answer
Consider the class definitions shown below:
public class Car {
private int mileage;
public Car() {
mileage = 0;
}
public void drive(int miles) {
mileage += miles;
}
}
public class ElectricCar extends Car {
private double battery;
public ElectricCar() {
battery = 100;
}
public void drive(int miles) {
/* Missing Code */
}
}
A Car
keeps track of the miles drive (mileage
). An ElectricCar
is a type of Car
that not only tracks the amount of miles drive, but also tracks the battery of life of the car, starting at 100% and is reduced every 4 miles driven. Which of the following would be an appropriate implementation of the drive
method in the ElectricCar
class?
A:
public void drive(int miles) {
battery -= (miles / 4.0);
mileage += miles;
}
B:
public void drive(int miles) {
battery -= (miles / 4.0);
super.drive();
}
C:
public void drive(int miles) {
battery -= (miles / 4.0);
super.drive(miles);
}
D:
public void drive(int miles) {
battery -= (miles / 4.0);
super(miles);
}
The correct answer would be C. Here is what is wrong with the other answers:
- A: the
ElectricCar
class doesn't have access tomileage
because it is a private variable inCar
- B: the
drive
method is being called incorrectly; it never received an integer argument. - D: the
super
keyword is being used incorrectly; it is trying to call the superclass constructor rather than an actual method.
9.5 - Creating References using Inheritance Hierarchies
Quick Vocab
A reference variable is considered polymorphic if it refers to different classes at different points in your code. A reference variable can store a reference to its declaread type, or to any subclass of the declared class.
Example
Lets use the following classes for an example:
public class Book {}
public class Novel extends Book {}
public class Poem extends Book {}
public class Epic extends Poem {}
As you can see, Novel
and Poem
are both subclasses of Book
, and Epic
is a subclass of Poem
. Look at the following declarations if we assume that each of the classes have a constructor with no parameters.
Book book1 = new Novel();
Book book2 = new Poem();
Poem book3 = new Epic();
Book book4 = new Epic();
All of these reference variables are polymorphic because instead of storing a reference to the declared type (Book
), they store a reference to a subclass of the declared type (Novel
, Poem
, or Epic
). The declared type and the actual reference (actual type) need to have an inheritance relationship in which the actual type is a subtype of the declared type.
Poem incorrect = new Book();
This declaration is incorrect because not all books are poems --> not all Book
objects are Poem
objects.
Practice Question 9.5.1
Scroll below prompt to see the answer
Take a look at the following classes:
public class Picture {
private String title;
public Picture() {
title = "Picture";
}
// Other methods
}
public class Painting extends Picture {
private String artist;
public Picture(String title, String artist) {
super(title);
this.artist = artist;
}
// Other methods
}
Declare an ArrayList
that can store references to objects of both Picture
and Painting
. Store a reference to a Picture
object with the title "sky" and store a reference to a Painting
object with the title "Mona Lisa" and the artist "Leonardo Da Vinci".
To make sure we can store both Picture
and Painting
objects, we need to declare the ArrayList
using the Picture
class so that we can store references of Picture
objects and subclasses of Picture
objects.
ArrayList<Picture> list = new ArrayList<>();
list.add(new Picture("sky"));
list.add(new Painting("Mona Lisa", "Leonardo Da Vinci"));
Practice Question 9.5.2
Scroll below the answer choices to see the answer
Consider the following class declarations:
public class Staff {
private String name;
private String position;
private double salary;
public Staff(String name, String position, double salary) {
this.name = name;
this.position = position;
this.salary = salary;
}
}
public class Sales extends Staff {
private String area;
public Sales(String name, String position, double salary, String area) {
super(name, position, salary);
this.area = area;
}
}
A different class contains the following method:
public void introduceSelf(Staff stf) {
// implementation not shown
}
Which of the following method calls is invalid?
A:
introduceSelf(new Staff("John", "Manager", 100000));
B:
Staff staff = new Sales("John", "Manager", 100000, "Plants");
introduceSelf(staff);
C:
Sales sales = new Sales("John", "Manager", 100000, "Plants");
introduceSelf(sales)
D:
introduceSelf(new Sales("John", "Manager", 100000, "Plants"));
E:
Sales sales = new Staff("John", "Manager", 100000);
introduceSelf(sales)
The correct answer choice is E because you can't declare a Sales
object and then reference a Staff
object. You can't go backwards in the inheritance hierarchy for polymorphism.
9.6 - Polymorphism
Quick Vocab
A method is polymorphic if it is declared in a superclass and overridden in a subclass. Polymorphism is when a non static overridden method that is executed at runtime from the correct class based on the object type.
Practice Question 9.6.1
Scroll below the answer choices to see the answer
Consider the following classes:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getDescription() {
System.out.println("I am a person with name " + name);
}
}
public class Student extends Person {
private int grade;
public Person(String name, int grade) {
super(name);
this.grade = grade;
}
public String getDescription() {
System.out.println("I am " + name + " and I am a student in grade " + grade);
}
public void study() {
System.out.println("Studying!");
}
}
The following code segment is occurs in another class different from Student
or Person
:
Person maria = new Student("Maria", 10);
System.out.println(maria.getDescription());
The following code segment is occurs in another class different from Student
or Person
and is supposed to display "I am a person with name Maria". Which of the following explains why it does not?
A. A compile time error occurs because maria
is declared as type Person
but instantiated as type Student
.
B. A compile time error occurs because getDescription()
is defined in both Person
and Student
C. getDescription()
is executed from Student
because maria
is instantiated as a Student
object, so "I am Maria and I am a student in grade 10" is displayed instead of only "I am a person with name Maria".
D. Because getDescription()
is defined in both Person
and Student
, both methods are executed and "I am a person with name Maria" and "I am Maria and I am a student in grade 10" are displayed on different lines.
The correct answer is C. A is not correct because a variable declared as a superclass can be a reference to a subclass. B is not correct because the process described in the choice is called method overriding, and it is allowed. D is not correct because a method is always called from the class that is referenced by the variable calling the method.
Note on Object Casting
Casting objects is not covered on the AP exam, but there have been previous MCQs in which the correct usage is to use object casting, but they don't do it. For example, if we have the following code:
Person alex = new Student("Alex", 8);
alex.study();
This code would not compile becuase the study()
method is not defined for the Person
object alex
. To fix this, we would first have to cast the object to a Student
, and then call the method.
((Student)alex).study();
9.7 - The Object
Superclass
Every class you write in Java extends the class Object
in the package java.lang
. For the AP Exam, you need to know how to use the toString()
and equals()
methods of the Object
class and how to override them.
The toString()
Method
The toString()
method returns a String representation of an object. It is executed if you are printing out an actual object and not calling any methods that return anything. Lets implement this method in the Person
class from the previous section:
public class Person {
// previous logic
@Override
public String toString() {
return "Person: " + name;
}
}
To invoke it, literally print out the object, and it will implicity call the toString()
method.
System.out.println(new Person("John"));
The main method would print out "Person: John" instead of the defaault implementation in the Object
class. If we printed out a Student
object, it would use the Person
class's toString()
method instead of the Object
class's because Person
is the next level up.
The equals()
Method
The equals()
method is another method in Object
that tests to see if two objects are equal. When overriding the method, you may need to use the instanceof
operator (not tested on AP Exam) to see if an object is an instance of a certain class. Lets implement the Person
class equals()
method:
public class Person {
// previous logic
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person person = (Person) obj;
return name.equals(person.name);
}
return false;
}
}
The syntax to call the equals()
method is:
Person person1 = new Person("John");
Person person2 = new Person("Jimmy");
System.out.println(person1.equals(person2));
Conclusion
This was a huge guide and I hope it helped you in some way. I highly reccomend using this guide other resources like AP Classroom to help you prepare for the AP Exam. Please share this with other AP CSA students because it will help them tremendously!
Sigining off 👋
Please email me if I have any typos in the guide or if something doesn't look right.