key words: static/dynamic type, method overriding vs. static method hiding
Every Java variable has two types:
| Type | Meaning | When determined |
|---|---|---|
| Static type | The declared type (what's on the left of the =) |
Compile time |
| Dynamic type | The actual type of the object created with new |
Run time |
Example: A fakeA = new B(); — static type is A, dynamic type is B. These can differ whenever B extends A.
public class A {
public void f() { System.out.println("A.f"); }
public static void g() { System.out.println("A.g"); }
}
public class B extends A {
public void f() { System.out.println("B.f"); }
public static void g() { System.out.println("B.g"); }
public static void h() { System.out.println("B.h"); }
}
A a = new A();
A fakeA = new B();
B b = new B();
f() is an instance method, so B.f() overrides A.f(). At runtime, Java looks at the object's actual (dynamic) type to decide which version runs — this is dynamic dispatch, implemented via a method table attached to the object itself.
a.f() → A.f (static type A, dynamic type A)fakeA.f() → B.f (dynamic type is B, even though declared as A)b.f() → B.fg() is static, so it belongs to the class, not to any object. B's g() does not override A's g() — it's a completely independent method that happens to share a name. This is called hiding, and it's resolved at compile time using the variable's declared (static) type only.
a.g() → A.gfakeA.g() → A.g — even though fakeA is dynamically a B, the compiler locks in A.g() because fakeA's declared type is A
But this is NOT considered in CS61B! We consider it as a bad style, which should be a syntax error though it doesn’t.
b.g() → B.gMental model: fakeA.g() is really just syntactic sugar for A.g(). Java doesn't even need an object to exist to call it.