Java多态性应用与实现方法

Java多态需同时满足继承(或实现)、方法重写、父类引用指向子类对象;重写须签名一致(协变返回除外);构造器中调用可重写方法会导致子类字段未初始化;instanceof+强转破坏多态,应优先使用统一接口方法。

多态性不是“写个接口就完事”

Java 中的多态性必须同时满足三个条件:继承(或实现)、方法重写、父类引用指向子类对象。只声明 interface 或只写 abstract class,但没在运行时用 Animal a = new Dog(); 这类上转型调用,就不算真正触发多态——编译器不会报错,但 a.speak() 调用的仍是父类默认逻辑或抛 UnsupportedOperationException

重写方法必须严格满足签名一致性

子类中 @Override 的方法,参数类型、数量、顺序、返回类型(协变返回除外)必须与父类完全一致。常见翻车点:

  • void print(String s) 在父类中,子类写成 void print(Object s) → 不是重写,是重载,多态失效
  • 父类方法抛 IOException,子类重写时抛 Exception → 编译失败
  • 父类返回 List,子类想返回 ArrayList → 可以(协变),但写成 Object 就不行

避免在构造器中调用可被重写的方法

这是隐藏极深的陷阱。当父类构造器执行期间调用一个被子类重写的方法,此时子类字段尚未初始化,可能得到 null 或默认值。

class Parent {
    String name = "parent";
    Parent() {
   

init(); // 此时 Child.name 还没赋值 } void init() { System.out.println(name); } } class Child extends Parent { String name = "child"; @Override void init() { System.out.println(name); } // 输出 null }

运行 new Child() 会打印 null。解决办法:把 init() 设为 final,或改用工厂方法延迟初始化。

立即学习“Java免费学习笔记(深入)”;

instanceof + 强转不是多态,而是破坏多态

if (obj instanceof Dog) { ((Dog)obj).fetch(); } 意味着你放弃了多态的扩展能力。一旦新增 Cat 类,就得改这里;再加 Bird,还要继续 if-else。正确做法是让所有子类实现统一接口方法:

interface Animal { void act(); }
class Dog implements Animal { public void act() { fetch(); } }
class Cat implements Animal { public void act() { meow(); } }

// 调用处保持干净
List animals = Arrays.asList(new Dog(), new Cat());
animals.forEach(Animal::act); // 自动分发,无需判断类型

真需要类型区分时(如日志、调试),优先用 getClass().getSimpleName(),而不是靠强转驱动业务逻辑。