1、多态的作用
在我们写继承时,对同一基类写继承,不同的子类可能需要重写不同的实现方法。
我们在调用这些方法时,因为这些方法所位于的类不同,又会写很多重载的代码,很不利于后期的维护修改。
这时就用到了我们的多态,举个例子比较一下:
public class Test {
public static void main(String[] args) {
funn(new Father());
funn(new Child1());
funn(new Child2());
}
static void funnn(Father p){ //多态的特性:可以根据父类去引用子类。
p.fun();
}
// 省去下面的重载代码:
// static void funnn(Child1 p){
// p.fun();
// }
// static void funnn(Child2 p){
// p.fun();
// }
}
class Father{
public void fun(){
System.out.println("执行Father类。");
}
}
class Child1 extends Father{
public void fun(){ //重写
System.out.println("执行Child1类。");
}
}
class Child2 extends Father{
public void fun(){ //重写
System.out.println("执行Child2类。");
}
}
执行结果:
执行Father类。
执行Child1类。
执行Child2类。
这段代码使用funnn方法时,统一接受一个Father类的引用,他和他的子类都传入funnn。
这里看似错误(将一种类型赋给了另一种类型),但实际上没有问题,因为Chid继承了Father,Child就是一种Father类型。编译器认可这条语句(过程中子类对象自动向上转型)。更特别的是,,接下来对Father引用类的调用,完全是根据赋值的类来实现的。对同一引用类,有不同的子类去实现它。这就是多态所表现出来的。
多态允许将多种类型(从同一基类导出的)视为同一类型来处理,这样同一份代码就可以毫无差别的运行在不同类型之上了。
那么在这种情况下,编译器怎么知道Father 的引用指向自己还是哪个子类的对象呢,编译器其实不知道。只有在运行的时候,才能确定是哪个类。
2、方法绑定
1、什么是绑定
绑定就是方法的调用和方法所属的类相关联,在调用时知道是哪个类的方法。
2、静态绑定(被privative,static,final修饰)
- private 无法被子类继承或访问。所以该方法只能和定义该方法的类绑定在一起。
- static 静态方法定义在静态区,访问时始终会访问自身的静态方法,,不随引用的对象而改变。
- final 无法重写。子类的中继承的方法是调用父类的方法。
- 这三个关键字修饰的方法叫做静态绑定(在编译时绑定)。
3、动态绑定
- 除了静态绑定之外,其他方法都是动态绑定(后期绑定、运行时绑定)——在程序运行时根据对象的实际类型能找到其相应的方法。
所以,多态其实是动态绑定的使用,而对于静态绑定,不能多态。
3、多态的优点
抽象类, 接口实现, 继承父类时进行方法的重写都可以使用多态。
- 提高复用性 :多态帮助我们节省了很多相似的代码,用同一基类调用处理。
- 可扩充,利于维护:在维护代码时,前面的代码始终是向后兼容的。出现新的子类,或修改某子类中的方法,只要方法及其参数是继承父类的,前面写的代码就都可以继续使用,不用对前面的代码做修改。
4、注意事项
1、父类引用指向的子类由于向上转型了,使用它只能访问父类中拥有的方法和属性,而对于子类中存在父类中不存在的方法,该引用是不能使用的。
2、多态是动态绑定的使用,静态绑定,不能使用多态(静态的方法是与类绑定,而不是对象)。
public class Father {
private void p(){
System.out.println('father');
}
public static void main(String[] args) {
Father f = new Child();
f.p(); //调用Father类中的p方法,输出father
}
}
class Child extends Father{
int a = 4;
void p(){ //非重写的同名函数p。
System.out.println('child');
}
}
3、方法的调用是多态的,但属性不是,任何属性的操作都是由编译器解析的,运行时不会具有多态性。
public class Test {
public static void main(String[] args) {
Father f = new Child();
System.out.println(f.a); //输出3
f.p(); //输出4
}
}
class Father{
int a = 3;
void p(){
System.out.println(a);
}
}
class Child extends Father{
int a = 4;
void p(){
System.out.println(a);
}
}