Java中的多态性是面向对象编程的三大特性之一,它允许不同的对象对同一消息做出不同的响应。多态性主要分为两种形式:方法的重载(Overloading)和方法的重写(Overriding)。然而,通常当我们谈论多态性时,我们更多地是指方法的重写和通过父类引用指向子类对象(即向上转型)的能力。
下面我将给出一个详细的例子来展示Java中的多态性,包括父类、子类、方法的重写以及向上转型。
首先,我们定义一个父类Animal:
public class Animal { // 父类的方法 public void eat() { System.out.println("Animal eats"); } // 父类的另一个方法,用于演示方法的重载 public void eat(String food) { System.out.println("Animal eats " + food); } // 父类的静态方法,静态方法无法被重写 public static void staticEat() { System.out.println("Static method of Animal eats"); } }
接着,我们定义一个子类Dog,它继承自Animal并重写了eat方法:
public class Dog extends Animal { // 子类重写父类的方法 @Override public void eat() { System.out.println("Dog eats dog food"); } // 子类新增的方法 public void bark() { System.out.println("Dog barks"); } }
现在,我们在主类Main中展示多态性的使用:
public class Main { public static void main(String[] args) { // 创建Animal对象 Animal animal = new Animal(); // 调用Animal的eat方法 animal.eat(); // 创建Dog对象 Dog dog = new Dog(); // 调用Dog的eat方法 dog.eat(); // 向上转型:将Dog对象赋值给Animal引用 Animal animalRefToDog = dog; // 调用通过Animal引用指向Dog对象的eat方法,展示多态性 animalRefToDog.eat(); // 输出的是Dog的eat方法的结果,而不是Animal的 // 尝试调用Dog特有的bark方法,这将导致编译错误 // 因为animalRefToDog是Animal类型,它不知道bark方法 // animalRefToDog.bark(); // 编译错误 // 静态方法无法被重写,因此即使通过Dog对象引用调用,也仍然是Animal的staticEat方法 animalRefToDog.staticEat(); // 输出的是Animal的staticEat方法的结果 // 方法的重载示例 animal.eat("apple"); // 调用Animal的eat(String)方法 // 注意:这里我们不能通过animalRefToDog.eat("apple")来调用Dog的eat(String)方法 // 因为Dog并没有定义eat(String)方法,所以它会调用Animal的eat(String)方法 // 如果Dog也定义了eat(String)方法,那么这里就会出现编译错误,因为AnimalRefToDog是Animal类型 // 正确的做法是在Dog类中定义eat(String)方法,并通过Dog对象来调用 // dog.eat("dog food"); // 如果Dog类中定义了此方法,这将调用Dog的eat(String)方法 } }
这个示例详细展示了Java中的多态性,包括方法的重写、向上转型以及方法的重载。注意,静态方法无法被重写,因此它们不具有多态性。同时,如果子类没有定义某个方法,那么通过父类引用调用该方法时,将调用父类中的该方法。