有关继承相关的内容在上一篇有介绍,有兴趣的话可以去看看
>>JAVA中的《继承和多态》(继承)
多态
可以简单理解为,对于同样的行为,不同的对象去做有不同的结果。
多态是同一个行为具有多个不同表现形式或形态的能力。
在java中要实现多态,必须要满足如下几个条件,缺一不可:
- 必须在继承体系下
- 子类必须要对父类中方法进行重写
- 通过父类的引用调用重写的方法
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。
1.1方法的重写
方法重写是指子类中的方法与父类中的某个方法具有相同的方法名、返回类型和参数列表。通过重写父类的方法,子类可以根据自己的需求对父类的方法进行扩展或修改,以实现更具体的行为。
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("猫发出喵喵声");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("狗发出汪汪声");
}
}
这里的@override的标签就代表这是个重写的方法
重写的规则
- 方法名必须相同:子类重写的方法与父类被重写的方法名称完全一致。
- 参数列表必须相同:参数的数量、类型和顺序都要与父类中被重写的方法一致。
- 返回类型必须相同或为子类型:如果父类方法的返回类型是原始类型,那么子类重写的方法的返回类型必须与父类相同;如果父类方法的返回类型是引用类型,那么子类重写的方法的返回类型可以是父类返回类型的子类型。
//原始类型
class Parent {
int getNumber() {
return 10;
}
}
class Child extends Parent {
// 必须返回 int 类型
@Override
int getNumber() {
return 20;
}
}
//引用类型
class Animal {
Animal getAnimal() {
return this;
}
}
class Dog extends Animal {
// 返回类型是父类返回类型的子类型
@Override
Dog getAnimal() {
return this;
}
}
- 访问权限不能低于父类方法:例如,如果父类方法是 public 访问权限,那么子类重写的方法不能是 protected、private 或默认访问权限。
重写的作用
- 实现多态性:通过方法重写,可以根据对象的实际类型来调用相应的方法,从而实现多态性。多态性使得程序在运行时能够根据对象的实际类型动态地选择要调用的方法,提高了程序的灵活性和可扩展性。
- 增强代码的可维护性:当父类的方法不能满足子类的需求时,可以通过重写父类的方法来实现子类的特定行为,而不需要修改父类的代码。这样可以保持父类代码的稳定性,同时也方便了代码的维护。
- 提高代码的复用性:父类中已经实现的方法可以被子类继承和重写,避免了代码的重复编写,提高了代码的复用性。
1.2 向上转型
在继承关系中,将一个子类对象赋值给父类引用,父类引用,引用了子类的对象,这种操作被称为向上转型。
多态允许使用父类引用调用子类重写的方法,在运行时根据实际对象的类型来确定调用哪个方法。
1.2.1 直接赋值
这里的父类引用子类对象就是直接赋值的方式.
1.2.2 方法的传参
将lion对象作为参数传给方法,用父类引用来接收。
1.2.3 返回值
将子类lion作为返回值,返回给以父类为返回值类型的方法。
1.2.4 向上转型的注意事项
向上转型无法调用子类独有的方法,只能调用父类中的方法。
有关动态绑定的介绍:
动态绑定:在 Java 中,动态绑定是一种在运行时根据对象的实际类型来确定调用哪个方法的机制,程序在编译的时候调用的是父类中的方法,但当代码运行的时候,通过父类的引用,实际上调用的是子类重写父类的方法,这种情况就叫动态绑定。
豆包关于Java实现动态绑定的解释:
Java 通过虚方法表来实现动态绑定。每个类都有一个虚方法表,其中记录了该类中所有可以被重写的方法的实际实现地址。当一个对象被创建时,它的内部会包含一个指向其所属类的虚方法表的指针。在运行时,当调用一个方法时,Java 虚拟机会根据对象的实际类型,通过该指针找到对应的虚方法表,并从中确定要调用的方法的实际地址。
由动态绑定我们要注意一点:不要在构造器中调用方法(如果这个方法是重写的,则会调用子类的重写方法,而我们在初始化对象时是从父类开始再到子类的,此时调用子类的方法而子类还没有初始,可能会出现)
1.3 向下转型
将一个子类对象经过向上转型之后当成父类对象使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转型
拿上面的例子说明,我们无法通过carnivore2这个父类引用来调用子类中的climbTrees方法。
我们将carnivore2强转成子类Leopard类型,便可以调用子类的独有方法了。
但是,我们知道,强转是有风险的,比如double类型转成int类型,是会造成数据丢失的,可以理解为,我可以把一个小盒子放在大盒子里,但不好把大盒子放小盒子里,会有风险,所以向下转型用到的机会不会很多。
Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
public static void main(String[] args) {
Carnivore carnivore1 = new Lion();
Carnivore carnivore2 = new Leopard();
if(carnivore2 instanceof Leopard){
((Leopard)carnivore2).climbTrees();
}
}
总结
本篇文章,接着上一篇JAVA中的《继承和多态》(继承)继续介绍了有关多态的知识,关于什么是方法的重写、什么是向上转型、向下转型,如果有什么不对的地方,还望指正,谢谢大家!!