Java三大特性之多态
多态的定义:指允许不同类的对象对同一个消息做出响应,即同一消息可以根据发送对象的不同采用多种行为方式。
就我个人经历来说,对一个新人一开始就理解这个定义还是有一点难度的(可能是我比较蠢)。我觉的还是用java的方式来理解可能会简单一点:
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
举个大家都熟悉的例子,《木兰诗》中有一句“双兔傍地走,安能辨我是雌雄”;雌兔(A)和雄兔(B)都是兔子(rabbit)的子类,但是双兔傍地走的时候你是分不出的,只有抓起来看看眼睛才能区别(雄兔脚扑朔,雌兔眼迷离)。下面我们可以用java代码来表示“双兔 ”:
Rabbit a = 雌兔;
Rabbit b= 雄兔;
在这里表现的就是多态,雌兔和雄兔都是兔子的子类,我们通过父类可以引用不同的子类-------我们只有在运行的时候才会直到引用类型所指向的具体实例对象
A a= new A();
这很容易理解,无非就是实例化了一个雌兔对象,但是你看下面这样呢???
Rabbit r= new A();
我们可以这样理解,这里定义了一个Rabbit r,它指向了 A 对象实例。由于A与Rabbit是继承关系,所以A可以向上转型成Rabbit,所以r是可以指向A的实例对象的。。。这样做有一个非常非常好的好处:在上一次继承中我们讲了,子类是父类的扩展,它可以提供比父类更为强大的功能,如果我们定义了一个指向子类的父类引用类型,那么他除了能引用父类的共性外,还可以使用子类强大的功能。
但是向上转型存在一些缺陷,就是它必然会导致一些方法属性的丢失,使我们不能够获取他们:所以就有:父类类型引用可以调用父类中定义的方法和属性,但是对于子类中的方法和属性就望尘莫及了
我们来看一下代码:
public class Rabbit{
public void fun1(){
System.out.println(" ------------------->Rabbit的fun1()")
public void fun2(){
System.out.println("----------Rabbit的fun2()")
}
}
}
public class A(){
/*
* 子类重载父类的方法,父类中不存在该方法,父类是不能引用该方法
*/
public void fun1(String a){
System.out.println("------------->A的fun1()")
}
/*
* 子类重写父类方法,指向子类的父类引用调用fun2()的时候必然会调用子类中的*fun2()
*/
public void fun2(){
System.out.println("----------->A的fun2()")
}
}
我们测试一下:
public class Test{
public static void main(String args[]){
Rabbit r = new A();
r.fun1();
r.fun2();
}
}
______________________________________________________________________
Output:
------------------------->Rabbit的fun1()
-------------------------->A的fun2()
所以对于多态我们可以初步总结如下:
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)
多态经典案例:
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
// 优先级由高到低依次为:
// this.clarify(O)、super.clarify(O)、this.clarify((super)O)、super.clarify((super)
// a2.clarify(b),a2是一个引用变量,类别为A,则this为a2,
// b是B的一个的举例,于是它到类A里面找clarify(B obj),没有找到,
// 于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.clarify((super)O),
// this仍然是a2,那里O为B,(super)O即(super)B即A,因此它到类A里面找clarify(A obj),
// 类A有那个窍门,但是由于a2引用的是类B的一个的对象,B覆盖了A的clarify(A
// obj)窍门,因此最终锁定到类B的clarify(A obj),输出为"B and A”
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
总结:
、多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
2、指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)
3、在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。即先查this对象的父类,没有就重头再查参数的父类
希望能给各位帮助~~~~(>_<)~~~~ !!!!!