加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java字节码

发布时间:2020-12-15 07:32:33 所属栏目:Java 来源:网络整理
导读:一、“一处编译到处运行” ? ? 原因就是字节码,由于不同的平台编译出来的机器码0,1是不同的,java采用不直接编译成机器码(0,1)而是把他们编译成字节码。再由不同平台上的JVM翻译成对应平台的机器码(0,1)。如今,JVM也不再只支持Java,由此衍生出了许多

一、“一处编译到处运行”

? ? 原因就是字节码,由于不同的平台编译出来的机器码0,1是不同的,java采用不直接编译成机器码(0,1)而是把他们编译成字节码。再由不同平台上的JVM翻译成对应平台的机器码(0,1)。如今,JVM也不再只支持Java,由此衍生出了许多基于JVM的编程语言,如Groovy,Scala,Koltin等等。

?

?

?而字节码命令所能提供的语义描述能力是要明显强于Java本身的,所以有其他一些同样基于JVM的语言能提供许多Java所不支持的语言特性。

二、如何看.class文件的十六进制文件格式

?

?

?用NotePad++直接打开显示乱码,我们点开插件--插件管理。然后选择上面标记的地方,然后点安装。

安装后重新打开.class文件,我们发现还是乱码。点插件---HEX-Editor然后选择View in HEX就可以了

三、如何看字节码文件,我们可以使用JDK提供的javap命令进行反编译.class,具体用法如下。实际过程中我们直接利用IDE看就可以了,例如IDEA直接选中java文件然后View---Show Bytecode就可以看了(首先这个java文件得编译,没有编译在Build中选重新编译一下即可)

四:解读字节码

package test;
public class ReadBytecode {
    private boolean bo;
    private byte b;
    private char c;
    private short s;
    private float f;
    private double d;
    private int i;
    private long l;
    private Integer id;
    private String name;
    public void m1(){}
    public int m2(){
        return 1;
    }
    public static void main(String[] args) {

    }
}


//字节码
// class version 52.0 (52)
// access flags 0x21
public class test/ReadBytecode {

  // compiled from: ReadBytecode.java

  // access flags 0x2
  private Z bo

  // access flags 0x2
  private B b

  // access flags 0x2
  private C c

  // access flags 0x2
  private S s

  // access flags 0x2
  private F f

  // access flags 0x2
  private D d

  // access flags 0x2
  private I i

  // access flags 0x2
  private J l

  // access flags 0x2
  private Ljava/lang/Integer; id

  // access flags 0x2
  private Ljava/lang/String; name

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public m1()V
   L0
    LINENUMBER 19 L0
    RETURN
   L1
    LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0
    MAXSTACK = 0
    MAXLOCALS = 1

  // access flags 0x1
  public m2()I
   L0
    LINENUMBER 21 L0
    ICONST_1
    IRETURN
   L1
    LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
    // parameter  args
   L0
    LINENUMBER 25 L0
    RETURN
   L1
    LOCALVARIABLE args [Ljava/lang/String; L0 L1 0
    MAXSTACK = 0
    MAXLOCALS = 1
}
View Code

?

?

分析上面代码我们可以得到,52是版本号代表java8,因为java的版本号从45开始,除1.0和1.1都是使用45.x外,以后每升一个大版本,版本号加一。也就是说,编译生成该class文件的jdk版本为1.8.0。

大多数的基本数据类型用其首字母大写 (除了long 类型用J,boolean用Z),引用类型用L表示并且以;结束。变量名会在后面写。方法返回值类型中多了V(void)。构造方法用<init>(参数列表)V表示。从主方法的参数我们可以看出数组用[lxx类型.? ?二位数组[[L依次类推。

分析上面的构造方法:

L0 L1是方法中字节码行号依次类推L2 L3。。。

LINENUMBER? ? ? ? ?字节码偏移量,即字节码和源码行数的偏移量。在发生异常的时候可以找到对应的源码位置(可以通过修改编译参数去掉,去掉的话出现异常编译器不会找到源代码异常发生处)

ALOAD 0? ? ? ? ? ? ? ? ?将引用型变量压入栈顶,此处是this。因为super()其实是this.supper()

INVOKESPECIAL? ?调用后面的方法

RETURN? ? ? ? ? ? ? ? ?弹栈

LOCALVARIABLE? ?帧栈中定义的局部变量与源码定义的变量之间的关系。如果没有这项信息(通过修改编译参数可以去掉),别人引用这个方法的时候无法获取参数名称,取而代之的是arg0,arg1这样的占位符。

每个实例方法中,都会有一个默认参数this.?LOCALVARIABLE? 后第一个参数为参数名称,第二个参数类型,第三第四个参数为这个参数在字节码中的可见行范围,最后一个参数表示这个参数在这个桢栈中的位置,例如上面的0。

MAXSTACK? ? ?最大操作数栈,JVM会根据这个值来分配栈桢中的操作栈深度,上面为1

MAXLOCALS? ?局部变量所需的存储空间,单位为Slot。Slot为JVM为局部变量分配内存的最小单位,大小为4个字节。这里的局部变量包括方法参数(包括隐藏的this)、方法内的局部变量、try--catch中catch()定义的参数。注意MAXLOCALS 并不一定等于所有局部变量的Slot和,因为局部变量中的Slot可以重用。

分析下面的m1()方法。很简单因为没有执行语句所以直接弹栈,MAXSTACK为0;

分析m2()方法:

? ?ICONST_1? ? 将int型1推送到栈顶

? ?IRETURN? ? ?从当前方法返回int型数据

分析主方法:由于是static 方法所以不会有this

更多字节码指令查询:https://blog.csdn.net/zqz_zqz/article/details/79484757

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读