Polymorphism: dynamic dispatch and toString() · 多态:动态分派与 toString()
Polymorphism: one type, many behaviours
- Polymorphism means "many forms": one superclass type, many subclass behaviours.
- You can hold a
Dogor aCatin anAnimalvariable, because each is-anAnimal. - When you call a method, the object's real type decides which version runs.
多态:一种类型,多种行为
- 多态(polymorphism)的意思是"多种形态":一个父类类型,多种子类行为。
- 你可以把一个
Dog或一个Cat放进一个Animal变量里,因为它们各自是一种Animal。 - 当你调用一个方法时,由对象的真实类型决定运行哪个版本。
Dynamic dispatch
- The variable's type (
Animal) decides which methods you are allowed to call. - But at run time, the actual object (
Dog) decides which overridden version runs. - This run-time choice is called dynamic dispatch — it is the heart of polymorphism.
动态分派
- 变量的类型(
Animal)决定你被允许调用哪些方法。 - 但在运行时,由实际的对象(
Dog)决定运行哪个被重写的版本。 - 这种运行时的选择叫作动态分派(dynamic dispatch) —— 它是多态的核心。
public class Main {
public static void main(String[] args) {
Animal[] zoo = { new Dog(), new Cat(), new Dog() };
for (Animal a : zoo) {
System.out.println(a.speak()); // Woof, then Meow, then Woof
}
}
}
class Animal {
public String speak() { return "some sound"; }
}
class Dog extends Animal {
public String speak() { return "Woof"; }
}
class Cat extends Animal {
public String speak() { return "Meow"; }
}
One loop handles every subclass
- The loop above never asks "is this a Dog or a Cat?" — it just calls
speak(). - Each object answers in its own way. That keeps the loop short and general.
- Add a brand-new subclass later and the same loop works on it, unchanged.
一个循环处理所有子类
- 上面的循环从不问"这是 Dog 还是 Cat?" —— 它只是调用
speak()。 - 每个对象用自己的方式回答。这让循环保持简短而通用。
- 以后再加一个全新的子类,同一个循环不用改就能处理它。
toString(): every object inherits it from Object
- Every class in Java secretly extends a class called
Object, which has atoString(). - Override
toString()to say how your object should look as text. - Java calls it automatically when you print an object or join it with
+.
toString():每个对象都从 Object 继承它
- Java 里每个类其实都暗中继承自一个叫
Object的类,它有一个toString()。 - 重写
toString(),来说明你的对象作为文本时应该长什么样。 - 当你打印一个对象,或用
+拼接它时,Java 会自动调用它。
public class Main {
public static void main(String[] args) {
Object x = new Fraction(3, 4);
System.out.println(x); // 3/4 -- toString() runs
System.out.println("ratio " + x); // ratio 3/4
}
}
class Fraction {
private int numerator;
private int denominator;
public Fraction(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public String toString() {
return numerator + "/" + denominator;
}
}
Common mistakes
- The actual object's method runs at run time (dynamic dispatch), not the variable's type.
- Override
toString()for readable output.
常见错误
- 运行时调用的是实际对象的方法(动态分派),而非变量的类型。
- 重写
toString()以得到可读的输出。
Now you try
- Use a superclass array, add a new subclass, and override
toString(). - A hidden Harness checks that the right version runs for each object.
- Press Run to compile, then Check answer. Your code runs on the server, so even the first run is fast.
现在轮到你
- 用一个父类数组、加一个新子类,再重写
toString()。 - 一个隐藏的 Harness(检查程序)会检查每个对象运行的是正确的版本。
- 按 Run 编译,然后 Check answer。你的代码在服务器上运行,所以第一次运行也很快。
Animal, Dog, and Cat are written for you. Complete the static method Zoo.chorus(Animal[] animals) so it returns every animal's sound joined by single spaces. Example: a Dog, Cat, Dog array gives "Woof Meow Woof". An empty array gives "". Loop and call speak() — let polymorphism pick the right sound. · Animal、Dog、Cat 已经为你写好。完成静态方法 Zoo.chorus(Animal[] animals),让它返回每个动物的叫声、用单个空格连接起来。例如:由 Dog、Cat、Dog 组成的数组得到 "Woof Meow Woof"。空数组得到 ""。循环并调用 speak() —— 让多态去挑选正确的叫声。
Click Run to see the output here. · 点击“运行”查看此处输出。
Animal, Dog, Cat, and a working Zoo.chorus are written for you. Add a class Cow that extends Animal and overrides speak() to return "Moo". Notice the existing chorus loop handles your new Cow with no changes. · Animal、Dog、Cat 以及一个能用的 Zoo.chorus 已经为你写好。添加一个继承自 Animal 的类 Cow,重写 speak() 返回 "Moo"。注意:现有的 chorus 循环无需任何改动就能处理你新加的 Cow。
Click Run to see the output here. · 点击“运行”查看此处输出。
Complete Fraction by overriding toString() so it returns the fraction as "numerator/denominator" — for 3 and 4 it returns "3/4". Java calls toString() automatically when you print a Fraction or join it with +. · 完成 Fraction,重写 toString(),让它把分数返回成 "分子/分母" 的形式 —— 当分子是 3、分母是 4 时返回 "3/4"。当你打印一个 Fraction 或用 + 拼接它时,Java 会自动调用 toString()。
Click Run to see the output here. · 点击“运行”查看此处输出。