java接口如何在内部实现? (虚函数表?)
C ++有多重inheritance。 在汇编级别实现多重inheritance可能相当复杂,但是在线上有很好的介绍如何正常完成(vtables,pointer fixups,thunk等)。
Java没有多个实现inheritance,但是它有多个接口inheritance,所以我不认为每个类都有一个单独的vtable可以实现这一点。 java如何在内部实现接口?
我意识到,与C ++相反,Java是Jit编译的,所以不同的代码段可能会有不同的优化,而不同的JVM可能会做不同的事情。 那么,是否有一些JVM遵循的一般策略,或者是否有人知道特定JVM中的实现?
另外JVM经常虚拟化和内联方法调用,在这种情况下根本就没有涉及到vtable或等价物,所以询问实现虚拟/接口方法调用的实际汇编序列是没有意义的,但是我认为大多数JVM仍然保留一些如果它们没有能够虚拟化所有的东西,那么可以使用类的一般表示。 这个假设是错误的吗? 这种表示看起来像一个C ++的vtable? 如果是的话,接口是否有单独的vtables,这些如何与类vtable相关联? 如果是这样,对象实例可以有多个vtable指针(类/接口vtables),就像C ++中的对象实例一样? 类types和接口types对同一对象的引用总是具有相同的二进制值,或者它们可以不同,就像在C ++中需要指针修正一样?
(仅供参考: 这个问题对CLR提出了类似的问题 ,在这篇msdn文章中似乎有一个很好的解释,尽pipe现在可能已经过时了,但我还没有find类似于Java的东西。
编辑:
- 我的意思是“实现”的意思是“GCC编译器如何实现整数加法/函数调用/等”,而不是“Java类ArrayList实现List接口”的含义。
- 我知道这是如何在JVM字节码级别上工作的,我想知道的是JVM在加载类文件和编译字节码之后生成的是什么样的代码和数据结构。
HotSpot JVM的关键特性是内联caching 。 这实际上并不意味着目标方法是内联的,而是意味着将一个假设放入JIT代码中,以后每次调用虚函数或接口方法时都会针对相同的实现(即调用位置是单态的)。 在这种情况下,检查是否被编译到机器代码中,这个假定是否实际成立(即目标对象的types是否与上次相同),然后将控制直接转移到目标方法 – 没有虚拟表参与其中。 如果断言失败,可能会尝试将其转换为一个megamorphic调用站点(即有多种可能的types); 如果这也失败了(或者是第一次调用),使用vtables(用于虚拟方法)和itable(用于接口)执行常规的冗长查找。
编辑 : 热点维基有更多关于vtable和itable存根的细节。 在多态的情况下,它仍然把一个内联的caching版本放入调用站点。 但是,代码实际上是一个在vtable中执行查找的存根,或者是一个可用的存根。 每个vtable偏移量(0,1,2,…)都有一个vtable存根。 在调用给定的偏移量之前, 接口调用会添加一个线性search,然后查看它(如果find)。