多态
booniez2024-04-22 23:46:56后台 Java继承
多态的前提
- 要有 继承/实现 关系
- 要有方法重写
- 要有父类的引用,指向子类对象
多态中成员访问特点
1. 构造方法
同继承一样,子类会通过 super
访问父类的构造方法
2. 成员变量
编译看左边(父类),执行看左边(父类),访问具有静态态绑定的特性。
- 静态绑定: 对成员变量的访问是在编译时决定的,这称为“静态绑定”。如果子类和父类中都定义了同名的成员变量,那么通过父类引用访问的是父类中的变量,即使这个引用指向的是一个子类对象。
- 不遵循多态性: 由于成员变量不具备多态性,它们的访问完全取决于引用变量的类型,而不是对象的实际类型。
3. 成员方法
编译看左边(父类),执行看右边(子类),访问具有动态绑定的特性。
- 动态绑定: Java的成员方法具有多态性,即子类对象可以直接调用父类中定义的方法。如果子类重写了父类的方法,当通过父类引用调用这个方法时,实际执行的是子类重写后的方法。这种机制称为“动态绑定”或“后期绑定”。
- 方法重载和重写: 重载发生在一个类中,方法的名字相同,但参数列表不同。重写则是子类提供了一个特定实现,这个实现覆盖了父类的方法。
为什么成员变量和成员方法的访问不一样? 因为成员方法有重写,成员变量没有
Java中的多态主要体现在对成员方法的调用上,而对成员变量的访问则不具备多态性。我们可以通过下面的特点来进一步理解多态在Java中成员变量和成员方法访问时的区别:
这里举一个简单的示例来说明这一点:
class Animal {
int legs = 4;
void display() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
int legs = 2;
void display() {
System.out.println("Dogs can walk and run");
}
}
public class TestPolymorphism {
public static void main(String[] args) {
// 使用父类类型的引用指向子类的对象
Animal myDog = new Dog();
myDog.display(); // 执行的是 Dog 的 display 方法
System.out.println(myDog.legs); // 访问的是 Animal 的 legs 变量
}
}
在上述例子中,myDog.display()
调用的是Dog
类中的display()
方法,体现了方法的多态性。但是,myDog.legs
访问的是Animal
类中定义的legs
变量,说明对于成员变量,并没有应用多态性,遵循的是静态绑定。
因此,在设计你的Java应用程序时,较好的做法是将需要多态行为的数据和行为定义为方法,并通过方法对这些数据进行访问和操作,以利用多态带来的灵活性和强大能力。
多态的优缺点
多态在Java中是一个核心概念,它为对象的操作提供了抽象层次,能够使程序更加灵活和可维护。但是,任何技术都有它的优势和劣势。以下是Java中多态性的一些优缺点:
1. 多态的优点
- 提高代码的可重用性: 通过多态,相同的方法或属性可以用在不同的对象上,这样可以减少代码量和提高代码的可重用性。
- 提高代码的可维护性: 多态通过分离做什么(定义在接口或抽象类中)和怎么去做(在具体子类中实现)来提高代码的可维护性,使得代码更加清晰,易于维护和扩展。
- 接口抽象: 使用接口和抽象类允许定义类型的抽象行为,而不是具体细节,这样客户端代码可以在不知道具体实现细节的情况下,使用类型的行为。
- 动态绑定: 动态绑定允许在运行时根据对象的实际类型来调用对应的方法,这样可以让程序具有更好的灵活性。
- 有助于实现松耦合设计: 多态有助于减少系统中各部分间的依赖关系,从而实现松耦合的设计。
2. 多态的缺点
- 牺牲性能: 由于多态需要在运行时确定调用哪个具体方法,可能会引入一些性能开销。虽然现代JVM优化了这一点,但在极高性能要求的场合,这可能是一个考虑因素。
- 增加复杂性: 使用多态可能会使代码逻辑变得更复杂,对于初学者来说可能难以理解。
- 限制访问子类特有的属性和方法: 当使用多态时,通常是通过父类类型的引用来操作对象,这限制了对子类特有成员的访问。
- 设计上的挑战: 正确使用多态需要在系统设计阶段就需要仔细考虑,如何抽象出合理的接口和类层次结构,以确保多态可以达到预期的效果。
在设计和实现Java应用程序时,应根据具体的应用场景和需求,权衡利用多态带来的好处与潜在的复杂性和性能考虑之间的平衡。通常,为了提高代码质量和未来的可扩展性,多态是推荐的做法。
多态中的类型转换
可以解决上面提到的限制访问子类特有的属性和方法
的问题。通过将父类强制转换成子类对象,就可以访问子类特有的方法
如果转换的时候,目标类型和实际类型不一致,会抛出ClassCastException
异常。因此建议先用 instanceof
进行类型判断
Powered by Waline v2.15.8