`

C++/Java 实现多态的方法(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中是不需要进行所谓的转换的。

分享到:
评论

相关推荐

    C++和Java多态的区别

    C++和Java多态的区别

    C++/java 继承类的多态详解及实例代码

    主要介绍了C++/java 继承类的多态详解及实例代码的相关资料,需要的朋友可以参考下

    C++中的多态与多重继承实现与Java的区别

    笔者校招面试时被问到了著名问题「C++ 与 Java 如何实现多态」,然后不幸翻车。过于著名反而没有去准备,只知道跟虚函数表有关。面试之后比较了 C++ 和 Java 多态的实现的异同,一并记录在这里。 C++ 多态的虚指针...

    c语言实现继承与多态

    虽然面向对象的设计并不会在很大程度上依赖于某种语言,但现代著作中提及面向对象的实现一般都认为是C++, Smalltalk, 或者Java。 本文从较底层的视角用面向过程的语言(比如C)对面向对象予以实现,这对于一些想运用...

    Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳

    Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳..........................

    C++与Java的不同.

    C++与Java的不同.通过对比,可以让那些由C++转java的人,了解两种语言的不同之处。特别是多态的方面。

    javaparser:基于函数式组合子逻辑的JAVA语言分析框架

    这个库的目的是要在java中提供一个类似parsec, spirit的库,这种组合子库并非c++的专利,java/c#也可以做到。这个库还将在java5.0上被改写,类型安全上它将也不再逊色于c++。 那么,为什么叫“函数式”呢?java是...

    优化Java中的多态代码

    编写Java代码时,我们通常使用接口、继承或者包装类(wrapper class)来实现多态,使软件更加灵活。不幸的是,多态会引入更多的调用,让Java的性能变得糟糕。部分问题是,Java不建议使用完全的内联代码,即使它是...

    Go语言实现类似c++中的多态功能实例

    Go本身不具有多态的特性,不能够像Java、C++那样编写多态类、多态方法。但是,使用Go可以编写具有多态功能的类绑定的方法。下面来一起看看吧

    Java 实现拼图游戏小案例

    1. 简单易学:Java 语言的语法和结构相对简单,与传统的 C/C++ 语言相比,去掉了一些复杂而容易出错的特性,使得初学者更容易上手。 2. 面向对象:Java 是一种纯粹的面向对象编程语言,支持封装、继承和多态等面向...

    文本编辑器的Java 实现小例子

    1. 简单易学:Java 语言的语法和结构相对简单,与传统的 C/C++ 语言相比,去掉了一些复杂而容易出错的特性,使得初学者更容易上手。 2. 面向对象:Java 是一种纯粹的面向对象编程语言,支持封装、继承和多态等面向...

    C++编程思想(《Thinking in C++》,Bruce Eckel著)

    全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...

    Python 的类、继承和多态详解

    最最基本的就是 __init__ 方法,相当于 C++ / Java 的构造函数。带双下划线 __ 的方法都是特殊方法,除了 __init__ 还有很多,后面会有介绍。 参数 self 相当于 C++ 的 this,表示当前实例,所有方法都有这个参数,...

    leetcode题库-Internship_Guidance:实习_指导

    leetcode题库 Internship_Guidance ...Java(多态、虚函数、继承)……。 整理的内容见note.pdf 算法题--重点 算法题也是面试中一大考点,没做出来的话,面试很难通过。 在做算法题的过程中,一定要注意与面试官多

    多态经典习题

    Java是一门面向对象的语言,抽象、跨平台、应用广,适合于广大应届毕业生、高中生学习。

    C++与Java语言对比

    从数据类型、概念性对比、OOP三大精神(封装、继承、多态)对比。

    棋牌的胡牌算法。实现 lua 、c++ 、c# 、golang 、js 、java 、python 版本.zip

    面向对象: Java是一种纯粹的面向对象编程语言,支持封装、继承和多态等面向对象的概念。这使得Java编写的代码更加模块化、可维护和可扩展。 多线程支持: Java内置了对多线程的支持,允许程序同时执行多个任务。这...

    java于c++的区别

    java和c++都是面向对象语言。也就是说,它都能够实现面向对象思想(继承,多态,封装)。

Global site tag (gtag.js) - Google Analytics