您的位置:首页 > 编程语言 > Java开发

java中多态性与动态绑定

2015-10-02 00:52 651 查看
一.多态的基本概念

多态性是面向对象的三大特性(封装、继承、多态)之一,多态可以理解为事物存在的多种体现形态,比如动物类(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息