Appearance
Lesson 02 · Inheritance & Polymorphism
Objectives
After this lesson you will be able to:
- Use
extendsandsuper, and tell overriding from hiding. - Predict polymorphic dispatch — which method actually runs.
- Override
Objectmethods (equals,hashCode,toString) correctly. - Use
final, casting, andinstanceofsafely.
extends and super
A subclass inherits accessible members and may add its own. A subclass constructor implicitly calls super() (the no-arg superclass constructor) as its first action unless you call super(...) or this(...) explicitly.
java
class Animal {
Animal(String name) { } // no no-arg constructor!
}
class Dog extends Animal {
Dog() { super("dog"); } // REQUIRED — Animal has no no-arg constructor
}Exam trap
If the superclass has no no-arg constructor, the subclass must call super(...) explicitly, or it won't compile (the implicit super() has nothing to call).
Overriding vs hiding
Overriding replaces an inherited instance method; dispatch is dynamic (based on the object's runtime type). Hiding applies to static methods and fields; resolution is static (based on the reference's compile-time type).
java
class A { String who() { return "A"; } static String s() { return "A.s"; } }
class B extends A {
@Override String who() { return "B"; } // overrides — dynamic
static String s() { return "B.s"; } // hides — static
}
A ref = new B();
ref.who(); // "B" — instance method, dynamic dispatch
ref.s(); // "A.s" — static method, resolved by the reference type AExam trap
Fields are never polymorphic — a field access uses the reference type, not the object type. With class A{int x=1;} class B extends A{int x=2;}, ((A) new B()).x is 1.
An override cannot reduce visibility, cannot throw broader checked exceptions, and its return type must be the same or a covariant (narrower) subtype. Use @Override so the compiler catches mistakes.
Object methods
Every class extends Object. Override these together and consistently:
equals(Object)— logical equality. If you override it, overridehashCodetoo, or hash-based collections break.hashCode()— equal objects must return equal hash codes.toString()— a readable representation.
java
@Override public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point p)) return false; // pattern: null-safe + cast in one
return x == p.x && y == p.y;
}
@Override public int hashCode() { return Objects.hash(x, y); }Gotcha
equals takes an Object parameter. Writing equals(Point p) overloads rather than overrides — collections still call the inherited Object.equals (identity). @Override would flag the mistake.
final, casting, instanceof
final on a class blocks subclassing; on a method blocks overriding. Downcasting needs a cast and is checked at runtime — a bad cast throws ClassCastException. Guard with instanceof (ideally the pattern form):
java
Object o = "hi";
if (o instanceof String s) { use(s.length()); } // safe, no separate cast
String bad = (String) Integer.valueOf(1); // ClassCastException at runtimeKey Takeaways
- A subclass constructor runs
super(...)first; if the parent lacks a no-arg constructor you must callsuper(args)explicitly. - Instance methods override (dynamic dispatch by object type); static methods and fields hide (resolved by reference type). Fields are never polymorphic.
- Overrides can't narrow visibility or broaden checked exceptions; return types may be covariant. Use
@Override. - Override
equals/hashCodetogether;equalsmust takeObjector it's just an overload. - Bad downcasts throw
ClassCastException— guard withinstanceof(pattern form casts for you).
Lesson Quiz
What does ref.who() and ref.s() print?
class A { String who(){return "A";} static String s(){return "A";} } class B extends A { String who(){return "B";} static String s(){return "B";} } A ref = new B();What is ((A) new B()).x ?
class A { int x = 1; } class B extends A { int x = 2; }Why does this subclass not compile?
class Animal { Animal(String n) {} } class Cat extends Animal { Cat() {} }You override equals but not hashCode. What breaks?
Which signature actually OVERRIDES Object.equals?
Next: Interfaces. Run the matching code in labs/src/main/java/com/jse21/m03_oop/.