目录
一、多态性的基本理解
二、Java 中多态性的体现:虚拟方法调用
编译时与执行时的行为差异
三、多态的使用前提
要有类的继承关系
要有类的重写
四、多态的适用性
五、多态的好处与弊端
好处
弊端
一、多态性的基本理解
多态性,简单来说,就是一个事物可以呈现出多种形态。就好比在现实生活中,一个人可以同时拥有多种身份,在不同的场景下展现出不同的行为特点。在 Java 编程的语境中,多态性使得同一个操作在不同的对象上会产生不同的执行结果,这为我们编写灵活且可维护性高的代码提供了强大的支持。
二、Java 中多态性的体现:虚拟方法调用
编译时与执行时的行为差异
在多态场景下调用方法时,会出现一种很有意思的现象。在编译阶段,Java 编译器会认为是在调用方法左边声明的父类的类型的方法。而到了执行时,实际指向执行的却是子类重写的那个方法。我们通常把这种情况简称为 “编译看左边,运行看右边”。
下面通过一个简单的代码案例来更好地理解这一点:
class Animal {public void makeSound() {System.out.println("动物发出声音");}
}class Dog extends Animal {@Overridepublic void makeSound() {System.out.println("汪汪汪");}
}class Cat extends Animal {@Overridepublic void makeSound() {System.out.println("喵喵喵");}
}public class Main {public static void main(String[] args) {Animal animal1 = new Dog();Animal animal2 = new Cat();animal1.makeSound(); // 编译时看作Animal类的makeSound方法,运行时执行Dog类重写的makeSound方法,输出:汪汪汪animal2.makeSound(); // 编译时看作Animal类的makeSound方法,运行时执行Cat类重写的makeSound方法,输出:喵喵喵}
}
在上述代码中,我们定义了Animal
类作为父类,Dog
和Cat
类作为子类并分别重写了makeSound
方法。在main
方法中,我们创建了Dog
和Cat
类的对象,但将它们声明为Animal
类型的引用。当调用makeSound
方法时,就体现了 “编译看左边,运行看右边” 的多态特性。
三、多态的使用前提
要在 Java 中实现多态,需要满足两个重要的前提条件:
要有类的继承关系
就像我们上面的例子中,Dog
和Cat
类继承自Animal
类一样。通过继承,子类可以继承父类的属性和方法,并且可以在这个基础上进行扩展和重写,这为多态性的实现奠定了基础。
要有类的重写
子类需要对父类的某些方法进行重写,以实现自己特定的行为逻辑。只有这样,在多态调用时,才能根据实际对象的类型执行子类重写后的方法,而不是仅仅执行父类的原始方法。
四、多态的适用性
多态性在 Java 中主要适用于方法,而不适用于属性。这是因为当我们通过父类引用指向子类对象时,虽然可以调用被子类重写的方法,但对于属性来说,访问的始终是父类中定义的属性(即使子类中可能也有同名属性)。例如:
class Parent {protected int value = 10;
}class Child extends Parent {protected int value = 20;
}public class Main {public static void main(String[] args) {Parent parent = new Child();System.out.println(parent.value); // 输出:10,访问的是父类的属性值}
}
在这个例子中,尽管创建的是Child
类的对象,但通过父类引用访问value
属性时,得到的是父类中定义的属性值。
五、多态的好处与弊端
好处
多态性为我们的代码带来了极大的便利,其最大的好处就是能够极大地减少代码的冗余。想象一下,如果没有多态,我们可能需要为不同类型的对象分别定义多个重载的方法来实现类似的功能。而有了多态,我们只需要在父类中定义一个通用的方法,然后让各个子类根据自身的需求重写该方法即可。这样不仅使代码更加简洁,也提高了代码的可维护性和扩展性。
弊端
然而,多态性也并非完美无缺。例如,当我们像这样创建对象:Person p2 = new Man();
(假设Man
是Person
的子类),在内存中虽然已经加载了Man
类中声明的特有的属性和方法,但由于声明为父类引用,导致我们没有办法直接调用Man
中加载的特有的属性和方法。也就是说,在多态的场景下,我们创建了子类的对象,也加载了子类特有的属性和方法,但因为引用类型是父类的,所以无法直接访问子类特有的那些属性和方法。这在某些情况下可能会给我们的编程带来一些不便,需要我们通过一些其他的方式(比如类型转换)来解决这个问题。