Java静态与动态类型参数的方法调用疑问(伯克利CS61B课程)
Hey there! Super glad you're diving deep into CS61B—these are exactly the kinds of questions that help solidify your understanding of Java's type system. Let's break down both of your questions one by one.
1. Why do Java parameters have different static and dynamic types?
First, let's clarify what each type means:
- Static type (compile-time type): This is the type you declare a variable to be, like
Animal myPet = new Dog();here,myPethas a static type ofAnimal. The compiler uses this type to check if you're calling valid methods (e.g., it'll yell at you if you try to callmyPet.bark()ifAnimaldoesn't define that method). - Dynamic type (runtime type): This is the actual type of the object the variable points to. In the example above,
myPet's dynamic type isDog—the object that's created at runtime.
So why have both? It's all about polymorphism and flexibility. Here's why it matters:
- It lets you write generic code that works with any subclass of a parent type. For example, a method that takes an
Animalcan accept aDog,Cat, or any other subclass, without needing separate methods for each. - It enables method overriding: when you call a method on a variable, the JVM uses the dynamic type to decide which implementation to run (e.g., if
Animalhas amakeSound()method andDogoverrides it,myPet.makeSound()will runDog's version at runtime).
Without separate static and dynamic types, we'd lose the ability to write flexible, reusable code that leverages inheritance.
2. Why does c.play(d) call Method D instead of Method E?
Let's unpack this scenario (I’m familiar with that CS61B example):
- You have a variable
dwith static typeDogand dynamic typeCorgi(soDog d = new Corgi();). - The
playmethod has two overloads: Method D isplay(Dog dog)and Method E isplay(Corgi corgi). - When you call
c.play(d), the compiler picks Method D at compile time, and the runtime sticks with that—even thoughdpoints to aCorgi.
The key here is understanding the difference between method overloading and method overriding:
- Method overriding: When a subclass provides its own implementation of a method that's already defined in the parent class. This uses dynamic binding—the JVM looks at the dynamic type of the object to decide which method to run.
- Method overloading: When multiple methods have the same name but different parameters (different types, number, or order). This uses static binding—the compiler decides which method to call based on the static types of the arguments at compile time.
In your example, play(Dog) and play(Corgi) are overloads, not overrides. So when you call c.play(d), the compiler only cares that d's static type is Dog—it doesn't know (or care) that at runtime, d will be a Corgi. Once it picks Method D during compilation, that's the method that gets executed at runtime, no matter what the dynamic type of d is.
If you wanted the runtime to pick Method E, you'd need to either:
- Declare
dwith a static type ofCorgi(soCorgi d = new Corgi();), or - Cast
dtoCorgiwhen calling the method:c.play((Corgi) d);
That way, the compiler sees the static type as Corgi and selects Method E.
内容的提问来源于stack exchange,提问作者mzoz

