多态存在的意义
-
多态的设计思想:(本质为"封装"的更进一步)
封装的目的:让类的使用者不需要知道类的实现细节,就能使用该类,但使用者仍应该知道该类是什么类型
*多态:*类的使用者不仅不需要知道类的实现细节,也不需要知道这个类究竟是什么类型,只需要知道有即将使用的方法即可 -
方便扩展:
新增一个类时,让子类去重写要使用的方法即可,类的调用者这里的代码不需要做出任何修改/只需做很小的修改 -
减少一些分支语句(if/else switch/case)
多态的实现::
- 向上转型
- 动态绑定
- 方法重写
注意:三者缺一不可
一、向上转型---------------“is-a”
- 所谓向上转型,就是使用父类的引用指向一个子类的实例(也可以说是子类的引用转成了父类的引用)
1、语法规则:
//方式一
Animal animal=null;
Cat cat=new Cat("喵喵");
animal=(Animal)cat;//不同类型的引用之间一般不可相互赋值(要进行强制类型转换),除非两者是父子关系
//所以此处(Animal)可省略
//方式二
Animal animal=new Cat("喵喵");
以上代码中,animal是父类Animal的引用,指向子类Cat的实例,这种写法为向上转型
2、发生的时机
- 直接赋值
Animal animal=new Cat("喵喵");
- 方法传参
public class Test {
public static void main(String[] args) {
Cat cat=new Cat("喵喵");
func(cat);
}
public static void func(Animal animal) {
}
}
- 方法返回
public class Test {
public static void main(String[] args) {
Animal animal=func();
}
public static Animal func() {
Cat cat=new Cat("喵喵");
return cat;
}
}
以上代码方法func返回的是一个Animal类型的引用,但实际对应到Cat的实例
注意:父类的引用只能访问到父类的属性和方法,访问不到子类独有的属性和方法,
若非要访问子类的属性,可借助方法重写,由父类的引用触发调用子类的方法,再由子类的方法间接操作子类的属性(方法重写后面会介绍)
二、动态绑定
1.发生时机
父类中包含的方法在子类中有同名,同参数,同返回值(特殊情况除外)的方法,就会进行动态绑定
例如:
父类:Animal
子类:Cat
二者共有同名,同参数,同返回值的eat()方法,在执行如下代码时就会触发动态绑定
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("1");
animal1.eat("food");
Animal animal2 = new Bird("2");
animal2.eat("food");
}
}
以上代码中,animal1调用的是父类的eat方法
animal2调用的是子类的eat方法
----------->在Java中,调用某个类的方法时,究竟执行的是父类方法的代码还是子类方法的代码,就要看这个引用指向的是父类的对象还是子类的对象,这个过程是程序运行时决定的,而不是在编译期决定的,因此这个过程被称为动态绑定
三、方法重写
-
对于上述提到的eat方法,子类实现父类的同名方法,并且参数类型和个数,返回值类型完全相同(特殊情况除外),这种情况被称为重写/覆写/覆盖,此时若通过父类调用该方法,就会触发重写,具体执行那个版本的方法就由动态绑定的规则来决定
-
注意事项:
1、普通方法可以重写,static修饰的静态方法不能重写
2、重写中子类方法的访问权限不能低于父类方法的访问权限
例如:将子类方法中的eat方法的权限改为private,编译就会出错
3、重写的方法返回值类型不一定和父类方法相同(特殊情况除外),最好写成相同的
4、在代码中进行重写方法时显示加上@Override注解,以便明确此处为方法重写 -
重载和重写的区别:
区别 | 重载 | 重写 |
---|---|---|
概念 | 方法名相同,参数类型及个数不同 | 方法名,参数类型及个数,返回值类型完全相同 |
范围 | 同一个类中 | 继承关系中 |
限制 | 没有权限要求 | 被重写的方法不能拥有比父类更加严格的访问控制权限 |
**注意:**方法的返回值类型并不影响重载,如果两个方法参数相同而返回值类型不同,会出现编译报错
-------------------------------------------------------------------------------------------------------------------------动态绑定和方法重写:
方法重写是Java语法层次上的规则,而动态绑定是方法重写这个语法规则的底层实现,两者本质上描述的是相同的事情,只是侧重点不同