`
329937021
  • 浏览: 124908 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java字节码学习之MethodInvoke

阅读更多
学习Java字节码有助于理解Java内存结构,加深对JVM的理解。



    首先需要知道JVM内存由堆、栈、方法区、本地方法栈组成。
    堆中存放JVM生命周期里所有的类的实例。
    栈中存放函数中的基础类型局部变量、函数中实例变量的引用。
    方法区存放Class、Method的信息以及Static的变量。
    本地方法栈存放调用本地方法时用到的变量。

    JVM为每个线程都分配了一个方法栈,方法栈包含不同方法的栈帧,每个方法都有一个栈帧,当前方法的栈帧称为当前栈帧,栈帧由局部变量区和操作数栈组成,所有线程共享堆中的数据。

    下面以一个简单的Java程序HelloWorld.java为例,介绍一下Java方法调用时的内存结构。

源代码
Java代码
public class HelloWorld {   
    private String myWorld;   
  
    public HelloWorld(String world) {   
        this.myWorld = world;   
    }   
  
    public String getMyWorld() {   
        return myWorld;   
    }   
  
    public void setMyWorld(String myWorld) {   
        this.myWorld = myWorld;   
    }   
       
    public boolean isNull(){   
        if(this.myWorld==null){   
            return true;   
        }else{   
            return false;   
        }   
    }   
       
    public static void main(String[]args){   
        HelloWorld myWorld = new HelloWorld("smallWorld");   
        boolean isNull = false;   
        myWorld.setMyWorld("bigWorld");   
        isNull = myWorld.isNull();   
    }   
}  

public class HelloWorld {
	private String myWorld;

	public HelloWorld(String world) {
		this.myWorld = world;
	}

	public String getMyWorld() {
		return myWorld;
	}

	public void setMyWorld(String myWorld) {
		this.myWorld = myWorld;
	}
	
	public boolean isNull(){
		if(this.myWorld==null){
			return true;
		}else{
			return false;
		}
	}
	
	public static void main(String[]args){
		HelloWorld myWorld = new HelloWorld("smallWorld");
		boolean isNull = false;
		myWorld.setMyWorld("bigWorld");
		isNull = myWorld.isNull();
	}
}


Javap -C HelloWorld

字节码:
Java代码
Compiled from "HelloWorld.java"  
public class com.sitech.core.HelloWorld extends java.lang.Object{   
public com.sitech.core.HelloWorld(java.lang.String);   
  Code:   
   0:   aload_0   
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V   
   4:   aload_0   
   5:   aload_1   
   6:   putfield        #13; //Field myWorld:Ljava/lang/String;   
   9:   return  
  
public java.lang.String getMyWorld();   
  Code:   
   0:   aload_0   
   1:   getfield        #13; //Field myWorld:Ljava/lang/String;   
   4:   areturn   
  
public void setMyWorld(java.lang.String);   
  Code:   
   0:   aload_0   
   1:   aload_1   
   2:   putfield        #13; //Field myWorld:Ljava/lang/String;   
   5:   return  
  
public boolean isNull();   
  Code:   
   0:   aload_0   
   1:   getfield        #13; //Field myWorld:Ljava/lang/String;   
   4:   ifnonnull       9  
   7:   iconst_1   
   8:   ireturn   
   9:   iconst_0   
   10:  ireturn   
  
public static void main(java.lang.String[]);   
  Code:   
   0:   new     #1; //class HelloWorld   
   3:   dup   
   4:   ldc     #27; //String smallWorld   
   6:   invokespecial   #29; //Method "<init>":(Ljava/lang/String;)V   
   9:   astore_1   
   10:  iconst_0   
   11:  istore_2   
   12:  aload_1   
   13:  ldc     #31; //String bigWorld   
   15:  invokevirtual   #33; //Method setMyWorld:(Ljava/lang/String;)V   
   18:  aload_1   
   19:  invokevirtual   #35; //Method isNull:()Z   
   22:  istore_2   
   23:  return  
  
}  

Compiled from "HelloWorld.java"
public class com.sitech.core.HelloWorld extends java.lang.Object{
public com.sitech.core.HelloWorld(java.lang.String);
  Code:
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1
   6:   putfield        #13; //Field myWorld:Ljava/lang/String;
   9:   return

public java.lang.String getMyWorld();
  Code:
   0:   aload_0
   1:   getfield        #13; //Field myWorld:Ljava/lang/String;
   4:   areturn

public void setMyWorld(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #13; //Field myWorld:Ljava/lang/String;
   5:   return

public boolean isNull();
  Code:
   0:   aload_0
   1:   getfield        #13; //Field myWorld:Ljava/lang/String;
   4:   ifnonnull       9
   7:   iconst_1
   8:   ireturn
   9:   iconst_0
   10:  ireturn

public static void main(java.lang.String[]);
  Code:
   0:   new     #1; //class HelloWorld
   3:   dup
   4:   ldc     #27; //String smallWorld
   6:   invokespecial   #29; //Method "<init>":(Ljava/lang/String;)V
   9:   astore_1
   10:  iconst_0
   11:  istore_2
   12:  aload_1
   13:  ldc     #31; //String bigWorld
   15:  invokevirtual   #33; //Method setMyWorld:(Ljava/lang/String;)V
   18:  aload_1
   19:  invokevirtual   #35; //Method isNull:()Z
   22:  istore_2
   23:  return

}


重点看一下main方法中调用isNull方法的操作:

Java代码
public static void main(java.lang.String[]);   
  Code:   
   0:   new           //在堆中分配内存,返回对象引用,压入操作数栈   
   3:   dup           //复制引用,压入栈   
   4:   ldc           //将常量池中的常量smallWorld压入栈   
                         //JVM会将main方法操作数栈中的变量弹出放入构造函数的    
                         //局部变量区   
   6:   invokespecial //调用构造函数,弹出对象引用和参数   
                         //调用结束后,JVM会将构造函数返回值压入main方法操作数栈   
   9:   astore_1      //将对象引用弹出,存储在main方法局部变量1的位置   
   10:  iconst_0      //将false值压栈   
   11:  istore_2      //弹出false并存储于main方法局部变量2的位置   
   12:  aload_1       //将对象引用压栈   
   13:  ldc           //将将常量池中的常量bigWorld压入栈   
                         //JVM会将main方法操作数栈中的变量弹出放入实例方法   
                         //的局部变量区   
   15:  invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数   
   18:  aload_1       //将对象引用存储在main方法局部变量1的位置   
                         //JVM会将main方法操作数栈中的变量弹出放入实例方法的   
                         //局部变量区   
   19:  invokevirtual //调用实例函数isNull,弹出对象引用和参数   
                         //调用结束后,JVM会将构造函数返回值压入main方法操作数栈   
   22:  istore_2      //弹出true并存储于main方法局部变量2的位置   
   23:  return  

public static void main(java.lang.String[]);
  Code:
   0:   new           //在堆中分配内存,返回对象引用,压入操作数栈
   3:   dup           //复制引用,压入栈
   4:   ldc           //将常量池中的常量smallWorld压入栈
                         //JVM会将main方法操作数栈中的变量弹出放入构造函数的 
                         //局部变量区
   6:   invokespecial //调用构造函数,弹出对象引用和参数
                         //调用结束后,JVM会将构造函数返回值压入main方法操作数栈
   9:   astore_1      //将对象引用弹出,存储在main方法局部变量1的位置
   10:  iconst_0      //将false值压栈
   11:  istore_2      //弹出false并存储于main方法局部变量2的位置
   12:  aload_1       //将对象引用压栈
   13:  ldc           //将将常量池中的常量bigWorld压入栈
                         //JVM会将main方法操作数栈中的变量弹出放入实例方法
                         //的局部变量区
   15:  invokevirtual //调用实例函数setMyWorld,弹出对象引用和参数
   18:  aload_1       //将对象引用存储在main方法局部变量1的位置
                         //JVM会将main方法操作数栈中的变量弹出放入实例方法的
                         //局部变量区
   19:  invokevirtual //调用实例函数isNull,弹出对象引用和参数
                         //调用结束后,JVM会将构造函数返回值压入main方法操作数栈
   22:  istore_2      //弹出true并存储于main方法局部变量2的位置
   23:  return


再来看看isNull方法:

Java代码
public boolean isNull();   
  Code:   
   0:   aload_0         //将局部变量区的对象引用参数压栈   
   1:   getfield        //访问堆区的类实例   
   4:   ifnonnull       //是否为空   
   7:   iconst_1        //如果是true,将1压入操作数栈   
   8:   ireturn   
   9:   iconst_0        //如果是false,将0压入操作数栈   
   10:  ireturn  

public boolean isNull();
  Code:
   0:   aload_0         //将局部变量区的对象引用参数压栈
   1:   getfield        //访问堆区的类实例
   4:   ifnonnull       //是否为空
   7:   iconst_1        //如果是true,将1压入操作数栈
   8:   ireturn
   9:   iconst_0        //如果是false,将0压入操作数栈
   10:  ireturn


方法调用结束后,JVM会将isNull操作数栈中的返回值压入main方法的操作数栈中。
分享到:
评论

相关推荐

    详解Java中Method的Invoke方法

    Java 中 Method 的 Invoke 方法详解 Java 中的 Method 对象提供了 invoke 方法,这个方法可以动态地调用 Java 方法。下面详细介绍了 invoke 方法的实现机制。 首先,在调用 invoke 方法之前,需要检查 ...

    java深度历险.pdf

    【Java深度历险——探索Java字节码操纵】 在Java编程世界中,深入理解Java字节码对于优化程序性能和实现高级功能至关重要。Java字节码是Java虚拟机(JVM)执行的基础,它是一种平台无关的中间表示,使得Java程序...

    java 中如何获取字节码文件的相关内容

    以下将详细讲解如何在Java中获取字节码文件的相关内容,包括构造函数、成员变量和成员函数。 一、获取字节码文件的构造函数 在Java中,我们可以使用`Class`类的`getConstructor`方法来获取指定类型的构造函数。...

    java与smali对比,翻译例子

    在Android系统中,Java字节码会通过DX工具转换为Dalvik字节码,也就是Smali代码,以适应Android的运行环境。 Smali是一种低级语言,它的语法结构和汇编语言类似,每条指令都对应DVM的特定操作。Smali代码是由反编译...

    四种动态生成Java代码的方法.rar

    `javax.tools.JavaCompiler`接口和相关类允许我们在运行时将源代码编译为字节码并加载到JVM。这种方式适用于需在运行时创建大量新代码的场景,如自定义脚本引擎。与前三种方式相比,它提供了编译时检查,但编译过程...

    Smali2JavaUI

    在Android应用开发中,Smali是一种低级的字节码语言,与Dalvik虚拟机的字节码格式相对应,而Java则是开发者通常使用的高级编程语言。当需要分析或修改已编译的APK时,Smali2JavaUI提供了便捷的桥梁,将二进制Smali...

    java7_invokedynamic_example

    `invokedynamic`是Java虚拟机(JVM)中的一个字节码指令,它允许程序在运行时动态地解析方法调用并执行。这个特性对于支持如JavaScript、Ruby等动态类型语言的Java实现,如JRuby和Rhino,以及Java自身的动态代理和...

    java jdk 动态代理演示demo2

    不过,由于Java的动态代理类是基于接口生成的,所以我们无法直接获取到它的字节码,除非先将代理类反编译为源代码,然后再编译成字节码。 总的来说,Java JDK动态代理为我们提供了一种灵活的方式,可以在不修改原有...

    Java串行程序并行化执行

    CGLIB(Code Generation Library)作为一款强大的Java字节码操作库,常常被用来实现这一目标。 CGLIB是一个高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。在并行化执行中,CGLIB可以帮助我们动态地...

    Java动态代理机制详解[整理].pdf

    Java虚拟机(JVM)负责加载类的字节码文件(.class文件)到内存中,并解析这些字节码,生成对应的Class对象。类加载器(ClassLoader)是这个过程中的关键角色,它负责定位并加载类的字节码。通常,JVM有三个内置的类...

    java 动态编译.java文件,动态运行类 _1.3

    通常情况下,Java程序在运行前需要通过`javac`命令将.java源文件编译成.class字节码文件,然后通过`java`命令执行。但在某些场合,我们可能希望在程序运行时动态地编译新的.java文件,以便快速响应代码变动。 Java...

    Java技术----实现JAVA的动态类载入机制

    在Java中,类加载器负责查找并加载类的字节码文件(.class文件)。这些字节码文件通常位于类路径(ClassPath)中定义的位置。Java虚拟机(JVM)有多个内置的类加载器,如Bootstrap ClassLoader、Extension ...

    基于Java实现的Shellcode加载器.zip

    1. **字节码注入**:首先,Shellcode需要被转换成Java字节码,因为Java虚拟机(JVM)只能理解和执行这种格式的代码。这可能涉及到对原始Shellcode的解析和转换。 2. **内存中的类定义**:加载器会创建一个新的Java...

    Java反射机制的详细讲解及实例,有助于java深度开发

    4. 字节码操作:ASM、Javassist等库用于动态生成和修改字节码,反射是其基础。 5. 测试工具:JUnit等测试框架利用反射调用私有方法或构造函数进行测试。 6. 反序列化:将序列化的对象数据反序列化为Java对象。 三、...

    Reflection_in_Java.zip_in_java 反射_java 反射机制_java反射_反射机制

    在编译期间,Java代码被转换为字节码,而反射是在运行时解析这些字节码的能力。这使得程序可以检查和修改自身的行为,增加代码的灵活性和可扩展性。 `Class`类是反射的核心,它代表了Java中的每一个类。我们可以...

    java 类加载器 加密

    Java 类加载器是Java运行时环境的一个重要组成部分,它的主要职责是将编译后的字节码(.class文件)加载到JVM中,使得程序能够运行。类加载器的机制保证了类的唯一性,同时也提供了灵活性,允许我们自定义加载逻辑。...

    Java 反射-动态代理

    CGLIB是基于ASM库,通过字节码技术动态生成子类来实现代理。Spring框架默认使用CGLIB作为AOP(面向切面编程)的底层实现。 动态代理的应用场景广泛,包括: - AOP:在不修改源代码的情况下,为方法添加预处理和后...

    Java反射机制的学习总结.docx

    尽管反射带来了很多便利,但它也有一定的性能成本,因为反射操作通常比直接的Java字节码执行要慢。因此,对于性能敏感的代码,应谨慎使用反射。 7. **注意事项**: 在使用反射时,需要注意安全性问题,因为反射...

    反编译—smali与java对比

    这种转换过程由DX工具完成,它将字节码转换为Smali指令,便于DVM执行。 Java是一种高级编程语言,具有丰富的类库和面向对象特性,如封装、继承和多态。它的语法清晰,易于理解和编写。例如,Java中的方法定义如下:...

    JAVA类加载机制与动态代理

    - **字节码操作库**:例如使用CGLIB、ASM等库自动生成代理类的字节码。 - **动态语言支持**:例如使用`java.lang.reflect.Proxy`类来创建动态代理类。 - **自定义代码生成**:通过编写代码来手动生成代理类的字节码...

Global site tag (gtag.js) - Google Analytics