`
小施_重名后缀
  • 浏览: 1306 次
社区版块
存档分类
最新评论

java接口方法调用源码分析

阅读更多
对于这样的java代码


pubic interface TestInterface {
  int foo();
  int foo1();
}

pubic interface TestClass implement TestInterface{
  public int foo(){
    int a  = 0;
    reurn a;
  }

   public int foo1(){
    int a  = 1;
    reurn a;
  }
}

TestInterface i = new TestClass();

i.foo();



javac之后会生成invoke_interface 的字节码.相关的实现位于templateTable::invokeInterface(int)生成的代码中.


java对象的的内存布局.

首先,变量i指向的内存布局是这样的.

[oopDesc][长度与类相关的内存区域]


oopDesc 包含2个成员, markWord和 klass.其中klass在未启用指针压缩时,指向该对象的类信息.
这个"类信息"不是java.lang.Class,而是虚拟机使用的内部数据.


klass指向的内存区域布局,参见(instanceKlass.hpp)

[klassOopDesc][instanceKlass][javaVtable][javaItable][静态成员][oop map]


klassOopDesc继承于oopDesc,添加了方法,但是没有新成员变量,所以内存结构一样.instanceKlass包含大量的类信息.其中,这里需要用到的就有 vtable_length, 其值就是javaVtable的长度.



[javaVtable] ==> vtable_length 个 method指针.
对于这里的例子,应该是以这个顺序

(Object类的方法)================
finalize
equals
toString
hashCode
clone
(TestClass类的方法)==
foo
foo1




java Itable内存布局,首先是该类说实现的所有接口类,以及该接口类的方法的偏移位置.最后以0表示接口类信息结束, 然后尾随的就是所有接口类的每个方法

interface0, offset
interface1, offset
.
.
.
interfacen, offset
0        0
========================
interface0_方法0
interface0_方法1
.
.
.
interface1_方法0
interface1_方法1
.
.
.


在上面的额示例代码里.itable就是


指向TestInterface指针, 偏移量---
0,                     0                |
指向foo方法的指针<--------------
指向foo1方法的指针



来看看invokeinterface的源码,

首先是和其他方法调用一样.
prepare_invoke()先去缓存找方法, 找不到就解析.连接


重点在这里
lookup_interface_method

movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));

//scan_temp = (instanceKlass*)(recv_klass+ sizeof(klassOopDesc) )->_vtable_len

lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));

//scan_temp =  recv_klass + vtable_base + scan_temp * sizeof(vtableEntry); // end of vtable, vtable的后面就是itable了


lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));

//recv_klass = recv_klass + itable_index * sizeof(itableMethodEntry) + offset_of(itableMethodEntry, _method)  @1


for (int peel = 1; peel >= 0; peel--) {
    movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
    cmpptr(intf_klass, method_result);

    if (peel) {
      jccb(Assembler::equal, found_method);
    } else {
      jccb(Assembler::notEqual, search);
      // (invert the test to fall through to found_method...)
    }

    if (!peel)  break;

    bind(search);

    // Check that the previous entry is non-null.  A null entry means that
    // the receiver class doesn't implement the interface, and wasn't the
    // same as when the caller was compiled.
    testptr(method_result, method_result);
    jcc(Assembler::zero, L_no_such_interface);
    addptr(scan_temp, scan_step);

	
  }

  bind(found_method);
//上面的代码简直坑爹展开一下


	movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
//method_result = scan_temp->_interface
    cmpptr(intf_klass, method_result);
	jccb(Assembler::equal, found_method);

//if(intf_klass == method_result)
 // goto found_method;

	bind(search);
	testptr(method_result, method_result);
    jcc(Assembler::zero, L_no_such_interface);
//if(method_result == 0)
//   goto L_no_such_interface;

    addptr(scan_temp, scan_step);
// scan_temp += sizeof(itableOffsetEntry);
	movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
//method_result = scan_temp->_interface
    cmpptr(intf_klass, method_result);
    jccb(Assembler::notEqual, search);
    //if(intf_klass != result)
//       goto search;



	 bind(found_method);

  // Got a hit.
  movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
  //scan_temp = ((itableOffsetEntry*)scan_temp)->_offset
  movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
  //method_result= recv_klass + scan_temp->_offset @2

//@1+@2 ==> 
//method_result = ((itableMethodEntry*)(recv_klass + scan_temp->_offset))[itable_index]._method



 for (scan = klass->itable(); scan->interface() != NULL; scan += sizeof(itableOffsetEntry)) {
     if (scan->interface() == intf) {
       result = (klass + scan->offset() + itable_index);
     }
   }






最后顺便提一句.vtable里是有接口方法的的.

所以类似
引用
TestClass t = new TestClass();//或者是TestClass的子类
t.foo();


这种事走vtable的,具体的javap看一下,他生成的是invokeVirtual


分享到:
评论

相关推荐

    java调用soap接口案例

    Java调用SOAP(Simple Object Access Protocol)接口是Web服务交互中的常见操作,SOAP是一种基于XML的协议,用于在Web上交换结构化的和类型化的信息。本案例主要关注如何使用Java来实现SOAP请求并获取响应,具体我们...

    Java xmlrpc远程方法调用(源码)

    5. **MyXMLRPC源码分析**: - `MyXMLRPC`可能包含了服务端和客户端的示例代码。 - 服务端代码可能包含一个实现XML-RPC接口的类,以及启动XML-RPC服务器的部分。 - 客户端代码可能包含创建XML-RPC客户端,设置...

    java调用新浪微博API接口源码

    总结来说,Java调用新浪微博API接口涉及OAuth2.0授权、API接口调用、源码解析和最佳实践等多个方面。了解并熟练掌握这些知识点,可以有效地实现Java应用与微博平台的交互,提供丰富的社交功能。

    java招商银行接口文档,源码

    4. **源码分析**:提供的源码可能是实现与招商银行接口交互的示例代码,或者是实际用于生产环境的代码。通过阅读和理解源码,开发者可以学习如何正确地构造请求,如何处理返回的数据,以及如何处理可能出现的异常...

    java源码分析

    从给定的文件片段中,我们可以提取出关于Java中Object类和String类的源码分析的知识点。 首先,Object类是Java中所有类的根类。它包含了所有对象共有的方法,是所有类继承结构的最顶层。从文件片段中我们可以看到...

    java调用matlab测试源码

    3. **Java调用MATLAB的工程**:这是核心部分,它会使用Java代码通过MATLAB Compiler生成的Java接口调用前面两个MATLAB工程中的功能。 在标签“java matlab 读图片”中,我们可以推断出Java工程的一个主要功能是读取...

    Java RMI 远程方法调用

    Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种分布式计算技术,它允许在不同的Java虚拟机之间进行方法调用,仿佛这些方法是在本地对象上执行一样。这个技术极大地简化了构建分布式应用的...

    Java编程方法学源码 Java源码 Java编程的艺术

    源码分析可以帮助理解如何利用反射进行类的动态加载、方法的调用等。 8. **JVM内部机制**:虽然Java源码不包括JVM本身,但通过阅读和分析使用JVM特性的代码,如内存管理、垃圾回收等,可以增进对JVM的理解。 9. **...

    飞信WebService接口调用源码

    飞信WebService接口调用源码是一份用于学习和开发飞信相关应用的重要资源。飞信,全称为“中国移动飞信”,是由中国移动推出的一款融合通信服务,它允许用户通过短信、语音、即时消息等多种方式在手机和电脑之间进行...

    java后端调用大华视频的demo

    6. **DEMO分析**:`DHTest.rar`和`java封装接口智能交通DEMO.zip`可能包含大华SDK的示例代码和Java接口的封装。分析这些DEMO可以帮助开发者快速理解和学习如何使用SDK,通常DEMO会提供基础的设备连接、视频流获取等...

    【精品】java调用短信外网接口服务端和客户端代码

    在IT行业中,调用外部接口是一项常见的任务...无论是服务端还是客户端,都需要对Java编程、网络通信和接口调用有一定的掌握。这个压缩包为开发者提供了一个良好的学习和实践平台,有助于提升其在实际项目中的应用能力。

    使用JNI进行混合编程:在Java中调用C/C++本地库

    JNI提供了一套接口,让Java虚拟机(JVM)能够调用本地方法,这些方法由C或C++编写,并编译成动态链接库(如Windows下的.dll或Linux下的.so文件)。JNI框架包括了Java端的本地方法声明和本地方法实现,以及C/C++端的...

    android调用webservice接口实现登陆源码

    本教程将深入探讨如何在Android中实现调用WebService接口进行登录功能,并基于提供的"login"源码进行分析。 首先,了解基础概念: 1. Android:Google开发的开源移动操作系统,主要应用于智能手机和平板电脑。 2. ...

    java调用c++生成so库

    1. **创建Java接口**:在Java代码中定义一个本地方法接口,这个接口将被C++代码实现。例如: ```java public class NativeDemo { static { System.loadLibrary("mylib"); } native void doSomething(); } ``...

    java witsml 客户端 源码

    Java WITSML客户端源码分析 WITSML(Well Intervention Transfer Format for Shared Data,井下作业数据共享格式)是一种开放标准,旨在促进油气行业的井下数据交换。它定义了一种结构化的方式,用于在不同软件系统...

    Java应用程序和java Web调用Matlab配置实例

    首先,要实现这一目标,你需要安装Matlab的Java接口,即MATLAB Compiler SDK。这个SDK允许开发者将Matlab代码编译为可独立运行的Java类或者组件,以便在Java环境中调用。安装完成后,确保你的Java项目能够正确引用...

    java调用dll或so库示例

    - **编写C++代码**:根据生成的头文件编写C++源码,实现本地方法的具体逻辑,并使用JNI函数调用Java代码。 - **编译本地代码**:为不同平台(Windows或Linux)编译本地代码,生成DLL或SO库。 - **加载库**:在...

    windows下java调用ffmpeg视频处理源码

    这些API允许Java代码直接调用FFmpeg的C/C++接口,使得Java应用程序能够处理视频文件。 2. **视频格式转换**:源码可能包含将视频从一种编码格式(如MP4)转换为另一种(如AVI)的功能。这涉及到理解不同的编码标准...

    java代理方法假设和验证的Proxy源码分析.docx

    本文将深入探讨Java代理方法的假设、验证以及Proxy类的源码分析。 首先,让我们理解Java代理的基本概念。在Java中,代理主要通过两种方式实现:接口代理(基于Java动态代理JDK Proxy)和类代理(基于CGLIB等库)。...

    搏天API接口调用网站源码分享源码资源下载整理.zip

    搏天API接口调用网站源码是一个用于与搏天API进行交互的软件开发资源,它提供了与搏天服务进行数据交换的功能。API(Application Programming Interface)是软件之间交互的桥梁,允许开发者通过发送请求获取所需的...

Global site tag (gtag.js) - Google Analytics