一.多态的基本概念
多态性是面向对象的三大特性(封装、继承、多态)之一,多态可以理解为事物存在的多种体现形态,比如动物类(Animal)中有猫类(Cat)、狗类(Dog),一只小猫可以称之为猫,也可以称之为小动物,所以创建对象时可以如下:
Cat x = new Cat();
Animal x = new Cat();
第二种创建方式便是多态的体现形式,即父类的引用指向了自己的子类对象
对象多态性:指的是父类对象和子类对象之间的转型操作
向上转型(自动完成):父类名称 父类对象 = 子类实例 例如:Animal x = new Cat();
class Animal{ //Animal类,父类
public void eat(){
System.out.println("Animal eat xx");
}
}
class Cat extends Animal{ //Cat类,子类
public void eat(){
System.out.println("Cat eat xx");
}
public void sleep(){
}
}
public class PolymorphismDemo{
public static void main(String[] args){
Animal x = new Cat();//向上转型
x.eat();
}
}
运行结果:
Cat eat xx
这里的执行过程是:首先检查父类中是否有eat()方法,如果没有,编译错误;如果有,则检查子类是否覆写了此方法。如果覆写了,则调用子类的eat()方法;如果没有覆写,则调用父类Animal中的eat()方法,后面会详细讲述动态绑定的过程
class Animal{ //Animal类,父类
public void eat(){
System.out.println("Animal eat xx");
}
}
class Cat extends Animal{ //Cat类,子类
public void eat(){
System.out.println("Cat eat xx");
}
public void sleep(){
}
}
public class PolymorphismDemo{
public static void main(String[] args){
Animal x = new Cat(); //向上转型
x.eat();
}
}
运行结果:
Animal eat xx
向下转型(强制完成):子类名称 子类对象 = (子类名称) 父类实例 例如:Cat c = (Cat) x;其中x为Animal实例,可见要完成向下转型,必须要有向上转型过程
class Animal{ //Animal类,父类
public void eat(){
System.out.println("Animal eat xx");
}
public void sing(){
System.out.println("Animal sing xx");
}
}
class Cat extends Animal{ //Cat类,子类
public void eat(){
System.out.println("Cat eat xx");
}
public void sleep(){
}
}
public class PolymorphismDemo{
public static void main(String[] args){
Animal x = new Cat(); //向下转型
Cat c = (Cat) x; //向下转型只能转向父类引用指向对象类型
c.eat();
c.sing();
}
}
这里的执行与普通的继承执行一样 ,要注意的是不能将 Animal x转型为Dog类型,因为它指向的是Cat实例
二.多态的前提
多态存在三个必要条件:
1.要么有继承,要么有实现
2.必须要覆写
3.必须要有向上转型过程,即父类引用指向子类对象,不然向下转型不知道将父类对象转成哪一种子类对象
这三点必须要记住!
三.动态绑定(参考Java核心技术卷一)
java当中的向上转型或者说多态是借助于动态绑定实现的,所以理解了动态绑定,也就搞定了向上转型和多态。
绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来,java中private方法,final方法,static方法或者构造器都是静态绑定实现的
静态绑定:在程序执行前已经绑定,由编译器或其他连接程序实现
动态绑定是指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
下面是调用对象方法的具体执行过程:
class Animal{ //Animal类,父类
public void eat(String name){
System.out.println("Animal eat xx");
}
}
class Cat extends Animal{ //Cat类,子类
public void eat(String name){ //吃啥
System.out.println("吃啥?:"+name);
}
public void eat(int num){ //吃的数量
System.out.println("吃几只老鼠?:"+num);
}
public void sing(){
System.out.println("唱歌");
}
}
public class PolymorphismDemo{
public static void main(String[] args){
Animal x = new Cat(); //向上转型
x.eat("mouse");
}
}
运行结果:
吃啥?:mouse
1.编译器查看对象的声明类型和方法名
假设我们调用x.f(param),且x声明为C类的对象,则编译器会例举出所有C类中的f的方法和父类、类中public修饰名为f的方法(父类的private方法不能访问)
2.编译器查看调用方法时提供的参数类型
如果在所有名为f的方法中存在一个与提供参数类型完全匹配的方法,就选择这个方法,这个过程叫做重载解析。例如,调用x.f("Hello")就会选择f(String)而不是f(int),如果没有找到与参数类型匹配的方法,或者发现经过类型转换后(int 可以转换成double,cat可以转换成animal)有多个方法与之匹配,则编译器报错
3.当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。
假设x的实际类型是D,它的父类是C,如果D类定义了f(String)那么该方法被调用(前提是父类有f(String)方法),否则就在D的父类中搜寻方法f(String),依次类推。这里D类是Cat类,C类是Animal类
总结:向上转型调用:
1.使用父类类型的引用指向子类的对象
2.该引用只能调用父类中定义的方法和变量
3.如果父类不存在此方法,则编译错误
4.子类存在此方法,且子类覆写了该方法,调用子类的这个方法(动态绑定)
5.子类不存在此方法,调用父类,依次类推
四.多态的例子
这个例子来源于http://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html,我觉得多态理解很有帮助
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {
return ("B and A");
}
}
class C extends B {
}
class D extends B {
}
public class PolymorphismDemo {
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();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
System.out.println(a2.show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
}
}
运行结果:
A and A
A and A
A and D
B and A
B and A
A and D
B and B
B and B
A and D
这里只对第四个输出做个说明:
实例对象为A,参数为B,本应执行A.class中show(A obj)(注意B是A的子类,所以可以看成A类)但是,B.class重写了show(A obj),所以执行B.class show(A obj)
这个过程其实就是动态绑定的实例,具体执行过程如下图:
参考资料:
http://www.cnblogs.com/mengdd/archive/2012/12/25/2832288.html
http://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html
http://blog.sina.com.cn/s/blog_600046120100wdza.html