多态是面向对象编程中的一个重要概念,指的是同一种方法在不同的对象上呈现出不同的行为。多态性分为两种类型:静态多态和动态多态。
静态多态: 静态多态指的是方法重载(Overloading)。在一个类中,我们可以定义多个方法名相同但参数列表不同的方法。当调用这些方法时,Java会根据传入的参数类型、数量、顺序来决定具体调用哪个方法。
动态多态: 动态多态指的则是继承和方法重写(Override)。当一个子类继承了父类,并覆盖了父类中某个方法时,如果使用父类引用变量指向子类对象,那么在调用这个被子类覆盖的方法时,实际上会执行子类中重写后的方法。
动态多态需要满足三个条件:
1. 继承关系:子类继承父类。
2. 方法重写:子类对父类中某个可访问的非 final 方法进行了重写。
3. 父类引用指向子类对象:使用父类引用变量进行实例化,并将其指向子类对象。
总之,通过实现继承和方法重写,我们可以在运行期间选择调用哪个具体实现。这使得代码更加灵活和可扩展,提高了程序的可读性和可维护性。
我们可以通过一个简单的代码示例来说明多态的概念。
假设我们有一个“动物”类(Animal)和两个子类:狗(Dog)和猫(Cat)。他们都有自己的“叫声”方法(makeSound),但是实现方式不同。
下面是 Animal 类的定义:
public class Animal {
public void makeSound() {
System.out.println("这是一个动物。");
}
}
Dog 类继承自 Animal 类,覆盖了 makeSound() 方法:
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
}
Cat 类也继承自 Animal 类,但是其 makeSound() 方法与 Dog 类不同:
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵!");
}
}
现在我们可以通过创建不同的对象来演示多态。假设我们有一个函数,接收一个 Animal 对象作为参数,并调用其 makeSound() 方法:
public void animalMakeSound(Animal animal) {
animal.makeSound();
}
当我们传入一个 Dog 对象时,调用的是 Dog 类中覆盖后的 makeSound() 方法。而当传入一个 Cat 对象时,则调用 Cat 类中重写后的方法。
例如:
Dog dog = new Dog();
Cat cat = new Cat();
animalMakeSound(dog); // 输出“汪汪汪!”
animalMakeSound(cat); // 输出“喵喵喵!”
完整代码为
public class Animal {
public void makeSound() {
System.out.println("动物发出叫声");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("狗发出汪汪的叫声");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("猫发出喵喵的叫声");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound();
animal2.makeSound();
}
}
这就是多态的应用,由于调用的具体实现取决于传入的对象类型,所以我们可以在不修改原有代码的情况下,通过传入不同的对象实现不同的行为。
其中@Override 是 Java 中的一个注解,用于表示当前方法是覆盖父类中的某个方法。
在 Java 中,子类可以重写(override)父类中的方法。当子类重写了父类的方法后,通过子类对象调用该方法时,会先调用子类中的实现。如果子类中没有重写该方法,则会直接调用父类中的实现。
使用 @Override 注解可以帮助开发者避免因为笔误、参数错误等原因导致无法正确地覆盖父类中的方法。如果标记了 @Override 注解但是实际上并没有覆盖任何父类中的方法,编译器会报错。
例如,在上面提到的动物继承树中,Dog和 Cat 类都使用了 @Override 注解来标记其重写了 Animal 类中的 makeSound() 方法:
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵!");
}
}
这样,在调用 Dog.makeSound() 或者 Cat.makeSound() 方法时,编译器就能够确定它们将会执行被覆盖后的代码。
不是必须写 @Override注解,但建议在覆盖(override)父类中的方法时使用该注解。使用 @Override 注解可以帮助开发者避免因为笔误、参数错误等原因导致无法正确地覆盖父类中的方法。如果标记了 `@Override` 注解但实际上并没有覆盖任何父类中的方法,编译器会报错。
虽然不是强制性要求,但是在重写(override)父类方法时使用 @Override 注解可以提高代码可读性和安全性。