AP Computer Science A Inheritance — Worked Answer Explanations

Unit 9 · 12 questions explained

Below is a complete answer key for our AP Computer Science A Inheritance practice questions. For each question you'll find the correct choice, a full written explanation of how to get there, and — for every wrong answer — a short note on exactly why it's tempting and where it goes wrong. Reading these straight through is one of the fastest ways to find the gaps in a unit before exam day.

Prefer to test yourself first? Take the timed Inheritance practice test and come back here to review, or head back to the Inheritance unit overview.

In-content ad
  1. Question 1 · Easy

    Given the following classes:

    public class Animal {
        public String speak() { return "..."; }
    }
    public class Dog extends Animal {
        public String speak() { return "Woof"; }
    }
    

    What does the following print?

    Animal a = new Dog();
    System.out.println(a.speak());
    
    • A
      ...
      Why not A: Used the declared type (Animal) to determine which method runs, ignoring runtime polymorphism.
    • B
      WoofCorrect
    • C
      Compile error: cannot assign Dog to Animal variable
      Why not C: A subclass object can always be assigned to a superclass variable (upcasting is automatic).
    • D
      ...Woof
      Why not D: Assumed both the superclass and subclass versions of speak() are called and concatenated.
    Explanation

    Java uses dynamic dispatch: the method called is determined by the actual runtime type of the object, not the declared type. The object is a Dog at runtime, so Dog's speak() returns "Woof".

    Key takeaway

    Polymorphism: the runtime type determines which overriding method executes, not the declared reference type.

  2. Question 2 · Easy

    Which keyword is used to indicate that one class inherits from another in Java?

    • A
      implements
      Why not A: implements is used for interfaces, not class-to-class inheritance.
    • B
      inherits
      Why not B: inherits is not a Java keyword; it exists in some other languages.
    • C
      extendsCorrect
    • D
      super
      Why not D: super is used inside a class to call a parent's constructor or method, not to declare inheritance.
    Explanation

    In Java, class Child extends Parent declares that Child inherits fields and methods from Parent. implements is for interfaces; super is for accessing parent members; inherits does not exist in Java.

    Key takeaway

    Use extends to declare class inheritance; use implements to adopt an interface.

  3. Question 3 · Easy

    What is the output of the following code?

    public class Shape {
        public String describe() { return "Shape"; }
    }
    public class Circle extends Shape {
        public String describe() { return super.describe() + "-Circle"; }
    }
    // In main:
    Circle c = new Circle();
    System.out.println(c.describe());
    
    • A
      Shape
      Why not A: Only printed the superclass result, ignoring Circle's additional "-Circle" concatenation.
    • B
      Circle
      Why not B: Only printed the subclass part, omitting the super.describe() prefix.
    • C
      Shape-CircleCorrect
    • D
      Compile error: super.describe() is not allowed
      Why not D: super.describe() is valid and commonly used to extend superclass behavior.
    Explanation

    Circle.describe() calls super.describe() which returns "Shape", then concatenates "-Circle" to produce "Shape-Circle". Using super allows a subclass to build on the superclass implementation.

    Key takeaway

    super.method() calls the parent class's version, allowing a subclass to extend rather than completely replace the parent's behavior.

  4. Question 4 · Easy

    Consider the following class hierarchy:

    public class Vehicle {
        private String brand;
        public Vehicle(String brand) { this.brand = brand; }
        public String getBrand() { return brand; }
    }
    public class Car extends Vehicle {
        private int doors;
        public Car(String brand, int doors) {
            super(brand);
            this.doors = doors;
        }
    }
    

    Which statement about Car's constructor is true?

    • A
      It will cause a compile error because Car does not declare the brand field.
      Why not A: Car passes brand to Vehicle via super(); it does not need to redeclare the field.
    • B
      The super(brand) call must be the last statement in the constructor.
      Why not B: super() must be the FIRST statement in a constructor, not the last.
    • C
      It correctly delegates brand initialization to the Vehicle constructor via super().Correct
    • D
      Without a no-arg constructor in Vehicle, this code will not compile.
      Why not D: Car explicitly calls super(brand), which matches Vehicle's one-arg constructor; a no-arg constructor is not required.
    Explanation

    super(brand) must appear as the first statement in the child constructor and invokes the parent's matching constructor. This correctly initializes the brand field that Vehicle owns. No no-arg constructor is needed because Car supplies the required argument.

    Key takeaway

    super(...) must be the first statement in a subclass constructor and delegates initialization to the matching parent constructor.

  5. Question 5 · Easy

    Which of the following best describes the difference between method overriding and method overloading?

    • A
      Overriding changes the return type; overloading changes the method name.
      Why not A: Overriding replaces a parent method with the same signature; overloading adds a same-named method with a different parameter list.
    • B
      Overriding occurs within the same class; overloading occurs across parent and child classes.
      Why not B: The definitions are reversed: overloading can occur in one class; overriding spans a parent-child relationship.
    • C
      Overriding redefines a parent's method with the same signature in a subclass; overloading defines multiple methods with the same name but different parameter lists.Correct
    • D
      Overriding and overloading are the same concept but use different keywords.
      Why not D: They are distinct concepts; overriding requires the same signature, while overloading requires different parameter lists.
    Explanation

    Overriding: a subclass provides a new implementation of an inherited method with the identical signature (name + parameter types). Overloading: the same class (or a related one) defines multiple methods with the same name but different parameter lists.

    Key takeaway

    Override = same signature, different class in hierarchy. Overload = same name, different parameter list.

  6. Question 6 · Easy

    Given the following code:

    Animal a = new Dog();
    if (a instanceof Dog) {
        System.out.println("Dog");
    } else {
        System.out.println("Not Dog");
    }
    

    What is printed, assuming Dog extends Animal?

    • A
      Not Dog
      Why not A: Checked the declared type (Animal) rather than the runtime object type (Dog).
    • B
      Compile error: cannot use instanceof with a parent type variable
      Why not B: instanceof works on any reference type; it is not restricted by the declared type of the variable.
    • C
      DogCorrect
    • D
      Runtime exception: ClassCastException
      Why not D: instanceof does not cast; it is a safe test and never throws a ClassCastException.
    Explanation

    instanceof checks the actual runtime type of the object. The object was created as new Dog(), so a instanceof Dog is true and "Dog" is printed. No cast occurs and no exception is thrown.

    Key takeaway

    instanceof checks the runtime type of an object, not the declared type of the variable holding it.

  7. Question 7 · Medium

    What is the result of the following code?

    public class A {
        public int value() { return 1; }
    }
    public class B extends A {
        public int value() { return 2; }
    }
    public class C extends B {
        // no override
    }
    // In main:
    A obj = new C();
    System.out.println(obj.value());
    
    • A
      1
      Why not A: Used A's version because the declared type is A, ignoring runtime polymorphism.
    • B
      2Correct
    • C
      Compile error: C does not define value()
      Why not C: C inherits value() from B; no compile error occurs.
    • D
      3
      Why not D: Assumed a sum or further modification of value() happens automatically through the chain.
    Explanation

    C inherits value() from B (which returns 2) because C does not override it. Dynamic dispatch uses C's most specific implementation, which is B's overriding version. A's version is never reached. Output: 2.

    Key takeaway

    A subclass inherits the most specific overriding method from its nearest ancestor that provides one.

  8. Question 8 · Medium

    A class declares public String toString(). Which statement is true about this method?

    • A
      It overloads the Object class's toString() because all classes implicitly extend Object.
      Why not A: It overRIDES (not overloads) toString(); the signature is identical to Object.toString().
    • B
      It overrides Object's toString() and is called automatically by print methods and string concatenation.Correct
    • C
      It must call super.toString() or a compile error occurs.
      Why not C: Calling super.toString() is optional; a complete custom implementation is valid on its own.
    • D
      It has no effect because Java does not use toString() automatically.
      Why not D: Java's println and string concatenation (+) automatically call toString() on objects.
    Explanation

    Every Java class implicitly extends Object. Declaring public String toString() with that exact signature overrides Object's version. Java's I/O methods (System.out.println, string concatenation) call toString() automatically on objects.

    Key takeaway

    Overriding toString() enables custom string representations used automatically by println and the + operator.

  9. Question 9 · Medium

    An abstract class Figure is defined as:

    public abstract class Figure {
        public abstract double area();
        public void printArea() {
            System.out.println("Area: " + area());
        }
    }
    

    Which of the following statements is true?

    • A
      new Figure() is valid because Figure has a concrete method.
      Why not A: Abstract classes cannot be instantiated regardless of whether they contain concrete methods.
    • B
      Any concrete subclass of Figure must provide an implementation of area().Correct
    • C
      Abstract classes cannot have concrete methods like printArea().
      Why not C: Abstract classes may contain any mix of abstract and concrete methods.
    • D
      printArea() will not compile because area() has no implementation in Figure.
      Why not D: Concrete methods in an abstract class may call abstract methods; the call resolves at runtime through dynamic dispatch.
    Explanation

    Abstract classes cannot be instantiated directly. Any non-abstract subclass must implement all abstract methods (here, area()). Abstract classes may freely contain concrete methods; printArea() calls area() which resolves polymorphically at runtime.

    Key takeaway

    Concrete subclasses of an abstract class must implement all abstract methods; abstract classes themselves cannot be instantiated.

  10. Question 10 · Hard

    Which of the following correctly demonstrates the use of equals() from the Object class, and when would you override it?

    public class Point {
        int x, y;
        public Point(int x, int y) { this.x = x; this.y = y; }
    }
    Point p1 = new Point(2, 3);
    Point p2 = new Point(2, 3);
    System.out.println(p1.equals(p2));
    
    • A
      Prints true because p1 and p2 have the same x and y values.
      Why not A: Object's default equals() compares references, not field values; p1 and p2 are different objects.
    • B
      Prints false; to get true, Point must override equals() to compare x and y.Correct
    • C
      Causes a compile error because equals() cannot be called on user-defined classes.
      Why not C: All Java classes inherit equals() from Object; it can always be called.
    • D
      Prints true only if the two objects were created in the same statement.
      Why not D: Reference equality depends on object identity, not how or when the object was created.
    Explanation

    Object's default equals() checks reference equality (same object in memory). Since p1 and p2 are distinct objects, p1.equals(p2) returns false. To compare by field values, Point must override equals() with a custom implementation comparing x and y.

    Key takeaway

    Object.equals() tests reference equality by default; override it to compare objects by meaningful field values.

  11. Question 11 · Hard

    Consider the following hierarchy:

    public class Vehicle { public void move() { System.out.println("Vehicle moves"); } }
    public class Boat extends Vehicle { public void move() { System.out.println("Boat sails"); } }
    public class AmphibiousVehicle extends Boat { }
    

    What is printed by:

    Vehicle v = new AmphibiousVehicle();
    v.move();
    
    • A
      Vehicle moves
      Why not A: Vehicle.move() is the declared type's version; dynamic dispatch resolves to the runtime type's nearest override.
    • B
      Boat sailsCorrect
    • C
      Vehicle movesBoat sails
      Why not C: Both versions are not called; only the most specific overriding method is executed.
    • D
      Compile error: AmphibiousVehicle does not define move()
      Why not D: AmphibiousVehicle inherits move() from Boat; no compile error occurs.
    Explanation

    AmphibiousVehicle does not override move(), so it inherits Boat's version. Dynamic dispatch for new AmphibiousVehicle() finds the nearest override, which is Boat.move(). Output: "Boat sails".

    Key takeaway

    Inherited methods resolve to the nearest ancestor's override; the runtime type's method lookup walks up the hierarchy until it finds an implementation.

  12. Question 12 · Hard

    A programmer writes:

    public class Printer {
        public void print(String s) { System.out.println(s); }
        public void print(int n) { System.out.println(n * 2); }
    }
    Printer p = new Printer();
    p.print(5);
    

    What is the output, and what concept does this demonstrate?

    • A
      Prints 5; demonstrates method overriding.
      Why not A: Method overriding involves a subclass redefining a parent's method with the same signature; these are two methods in the same class with different parameter types.
    • B
      Compile error: two methods cannot have the same name.
      Why not B: Java allows multiple methods with the same name as long as they have different parameter lists (overloading).
    • C
      Prints 10; demonstrates method overloading.Correct
    • D
      Prints 5; demonstrates polymorphism through inheritance.
      Why not D: Overloading is resolved at compile time by the argument type; p.print(5) matches print(int) and prints n*2 = 10, not 5.
    Explanation

    Two methods named print in the same class with different parameter types (String vs int) is method overloading. p.print(5) resolves to print(int) at compile time, executing 5 * 2 = 10. Output: 10.

    Key takeaway

    Overloading is compile-time resolution by parameter type; calling print(5) dispatches to print(int), not print(String).