多态(Polymorphism)的兑现机制(下)--Java篇

  
既然多态是面向对象的老三挺精神特征有(其它少个凡是数据抽象和继承),那么C++为什么非将艺术调用的默认方式设置为动态绑定,而使经主要字
virtual进行标记为?Bruce Eckel在《Thinking in
C++》中关系,这是由于历史原因造成的,C++是起C发展而来的,而C程序员最为关切的是性问题,由于动态绑定比静态绑定多几长达指令,性能兼备下滑,
如果将动态绑定设定也默认方法调用方式,那么多C程序员可能未会见承受,因此,C++就将动态绑定定位成可选取的,并且作出保证:If
you don’t use it, you don’t pay for it(Stroustrup)。
   
但是,Java作一个全新的全面向对象的言语,并无设有向下兼容的问题,同时,Java的设计者也觉得多态作为面向面向对象的中心,面向对象语言应该提供放置的支持,因此,Java将动态绑定作为艺术调用的默认方式。
    下面,我们就详细地来了解一下Java是安呢多态提供支持之。
与C++一样,Java中呢发生一个存放实例方法地址的数据结构,在C++中,我们管其称作VTable,而在java中方法表(Method
Table),但是两岸发生众多一模一样的处:
     1、它们的图是千篇一律之,同样用来救助实现方式的动态绑定。
     2、同样是类似级别之数据结构,一个看似的具备目标共享一个方法表。
     3、都是经偏移量在该数据结构中找找某一个方法。
    
4、同样保证拥有派生类中延续给基类的不二法门以方表中的偏移量跟该办法在基类方法表中的偏移量保持一致。
     5、方法发明中还不得不存放多态方法(Java中之实例方法,C++中是vitual方法)。

    
但是总,C++是相同山头编译型的语言,而Java更加偏向于解析型的,因此上述数据结构的变迁与保安是截然不同的,表现于:
    
1、C++中VTable和vptr是当编译阶段由编译器自动生成的,也就是说,在C++程序载入内存以前,在.obj(.o)文件被早已发这些构造的信
息;Java中之办法发明是由于JVM生成的,因此,使用javac命令编译后生成的.class文件被并从未辙发明底音。只有当JVM把.class文件
载入到内存中时,才见面为该.class文件动态变化一个暨的提到的方法表,放置在JVM的方法区中。
   
2、C++中有方法以VTable的索引号是以编译阶段都明显知道之,并不需要在运行过程遭到动态获知;Java中的计初始时犹只是一个记,并无是
一个明确的地址,只有等及该方式给第一不行调动用时,才见面让解析成一个方法表中的偏移量,也就是说,只有以此时,实例方法才判知道好在方发表着之偏移
量了,在即时之前须经历一个解析的进程。

   
此外,Java中莫支持多双重继承,也便无会见像C++那样在是泥潭中纠缠不清了,但Java也引入了初的定义,那便是接口,Interface。使用Interface调用一个实例方法及用一个Class来调用的进程是匪一样的:

public class  Zoo
{
 public static void main(String[] args)
 {
   Pet p1 = new Dog();
   Pet p2 = new Dog();
   p1.say(); //首先解析一差,得到偏移量,调用方法
   p2.say(); //不用解析,直接以上次的获得的偏移量,调用

  Cute c1 = new Dog();  
  Cute c2 = new Dog();
  c1.cute(); 
//这里以接口来调用实例方法,首先同样会分析一次于,得到偏移量,调用相应措施
  c2.cute(); //这里虽然上次曾经解析了了,但是要得重新和上次一律又分析一不善,得到偏移量,调用
 }
}

interface Cute
{
 public void cute();
}

class Pet
{
  public void say(){ System.out.println(“Pet say”);  }
}

class Dog extends Pet implements Cute
{
     public void cute(){ System.out.println(“Dog cute”); }
     public void say(){ System.out.println(“Dog say”);  }
}

   
为什么会生这么的界别吧?这是坐实现与一个接口的类似并无可知确保还是起同一个超类继承的,而且此超类也一样实现均等之接口。因此,该接口声明的办法并无克还管处于方法表中的和一个职及。如,可以定义下面的类:

class Cat  implements Cute
{
     public void cute(){ System.out.println(“Cat cute”); }
}

   
那么,Dog跟Cat同样都落实了接口Cute,因此还能用Cute接口进行调用,但是方法cute在Dog方法表中的位置并无可知确保该措施在Cat方
法表中的职位是一样的。因此,对于接口调用方法,我们只能每次都再次分析一道,获得纯粹之偏移量,再开展调用了。这为招致了采取接口调用方法的效率要较要
用类调用实例方法没有。当然,这仅是对立而言,JVM在促成达标会赋予优化,我们无能够说以接口效率低就不应用了,相反由于当面向对象作用受到接口的精作
用,java是发起用接口的,这等同触及我们是内需专注的。
   
还有一些,虽然java不支持类的多重继承,但是是得兑现多单接口的,那么,在Java中会无见面使像C++的比比皆是继承那样进行必要的变换为?这个问题,
我们才待想转手两端调用的求实过程,就可知懂得,Java的接口方法每次调用前都是需要分析的,在此地才会博得实在的偏移量,这同C++中编译期间得到偏移
量是匪雷同,因此,在Java中是勿需要开展所谓的转移的。
转http://hi.baidu.com/daping\_zhang/blog/item/e0360d333f33fbf81a4cffaa.html/cmtid/928ebd3e145bb4f2828b13a9\#928ebd3e145bb4f2828b13a9