CodeGym /课程 /JAVA 25 SELF /在实践中使用多态

在实践中使用多态

JAVA 25 SELF
第 18 级 , 课程 3
可用

1. 集合中的多态:为什么需要它?

先从一个问题开始:“在真实的程序里,为什么需要多态?”

想象一下动物园。你有一个基类 Animal,以及一堆子类:DogCatCowParrot,甚至还有 Platypus(鸭嘴兽,给喜爱异域风情的人)。它们都会发出声音(makeSound()),但实现各不相同。

与其为每种动物创建单独的数组,不如声明一个 Animal 类型的数组或列表,把谁都可以放进去:

Animal[] animals = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Parrot()
};

现在你可以遍历这个数组,并为每个元素调用 makeSound()

for (Animal animal : animals) {
    animal.makeSound();
}

魔法!每个对象都知道该发出什么声音,你无需写一堆 ifswitch

类比示例

就好像你对一群动物下达“发声!”的命令,每个动物都会自己决定怎么做:狗会汪汪叫,猫会喵喵叫,而牛会哞哞叫。你不需要确认它们是谁——只需调用同一个方法。

2. 实战示例:员工层次结构

来一个更贴近现实(也贴近你未来的 IT 工作)的例子。假设公司里有不同的员工:经理、开发、测试。每个人都有 work() 方法,但实现不同。

声明基类

public class Employee {
    public void work() {
        System.out.println("员工在工作...");
    }
}

子类

public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("经理正在开会。");
    }
}

public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("开发人员在写代码。");
    }
}

public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("测试人员在查找 bug。");
    }
}

使用基类型的数组/列表

public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work(); // 对每个对象都会调用 "正确" 的方法版本
        }
    }
}

运行结果:

经理正在开会。
开发人员在写代码。
测试人员在查找 bug。
开发人员在写代码。

有什么好处?

  • 不用写大量类似“如果是 Developer — 就做某某”的分支检查。
  • 要添加一种新员工(例如 Designer)— 只需创建一个新类并把它放进数组即可。
  • 使用员工数组的那部分代码完全不用改!

3. 多态的优势:灵活性与可扩展性

假设你的公司新增了一种员工类型 — Designer。你需要做的只是创建一个新类:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("设计师在绘制原型。");
    }
}

现在把设计师加入团队:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

搞定!程序会立刻正确处理这个新员工类型,而无需改动那段遍历数组并调用 work() 的代码一行。

这就是可扩展性:你的代码可以轻松适配新的对象类型。

4. 多态的限制:硬币的另一面

遗憾的是,任何“魔法”都有其限制(就像 RPG 里一样也要付出代价)。

只能访问基类中声明的方法

当你通过 Employee 类型的变量工作时,只能调用在 Employee 类中声明的方法。如果 Developer 有一个专有方法 writeCode(),你不能直接调用它:

Employee e = new Developer();
// e.writeCode(); // 编译错误:Employee 中没有这个方法!

如果你非常想调用这个特有方法,就得进行类型转换。但这只是下下策。如果你经常需要做类型转换,可能应当重新审视类的设计——基类或接口应包含所需的方法。

if (e instanceof Developer) {
    Developer dev = (Developer) e;
    dev.writeCode();
}

但这样就失去了本应有的通用性与优雅。因此,尽量把基类设计为只包含所有子类都真正需要的方法。

5. 动手实践:实现员工层次结构

来做个小应用:包含若干种员工类型,并用多态对其进行处理。

步骤 1:基类与子类

// Employee.java
public class Employee {
    public void work() {
        System.out.println("员工在工作...");
    }
}

// Manager.java
public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("经理正在开会。");
    }
}

// Developer.java
public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("开发人员在写代码。");
    }
}

// Tester.java
public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("测试人员在查找 bug。");
    }
}

步骤 2:主类

// CompanyDemo.java
public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work();
        }
    }
}

步骤 3:加入可扩展性

假设一个月后公司来了新同事——设计师。你需要做的只是:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("设计师在绘制原型。");
    }
}

好了,现在把设计师加入团队:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

小结

主体代码(CompanyDemo)保持不变!这就是多态的力量。

6. 使用多态时的常见错误

错误 1:期望通过基类引用访问子类的特有方法。
初学者常会尝试通过超类类型的变量调用子类的特有方法。例如:

Employee e = new Developer();
// e.writeCode(); // 错误!Employee 中没有定义该方法。

要调用特有方法必须进行类型转换,但这会损失通用性。

错误 2:未使用注解 @Override
如果忘记该注解,可能会因为命名拼写等问题写出一个新方法而不是重写。这样一来多态就不会生效,将会调用父类版本。

错误 3:缺少共同的接口。
如果基类没有包含所需的方法,多态就无从谈起。比如,如果在 Employee 中没有 work() 方法,那么遍历员工数组的循环就无法为所有对象调用该方法。

错误 4:违反开闭原则。
如果为了添加新的员工类型不得不修改遍历数组/列表的代码——说明你没有正确地使用多态。

评论 (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
ncksllpo 级别 43,Cherkasy,Ukraine
3 二月 2026
🍇