天天看點

.class檔案了解

原java檔案:

package com.jyds;

/**
 *  * Created by jl on 2018/7/26 0026
 *   */
public class Test {
    public static void main(String[] args) {
        String a = "1";
        String b = "2";
        String c = a+b;
    }
}
           

javac編譯後的class檔案:

cafe babe 0000 0034 002e 0a00 0900 1509

0016 0017 0700 180a 0003 0015 0a00 0300

1908 001a 0a00 0300 1b0a 0003 001c 0700

1d0a 001e 001f 0a00 0300 2007 0021 0100

063c 696e 6974 3e01 0003 2829 5601 0004

436f 6465 0100 0f4c 696e 654e 756d 6265

7254 6162 6c65 0100 046d 6169 6e01 0016 ...

javap -verbose 将.class檔案反編譯為可讀的位元組碼并輸出:

Classfile /home/ljiang/com/jyds/Test.class
  Last modified Jul 26, 2018; size 458 bytes
  MD5 checksum 5bd08e536acec4ae68ee147fee12e206
  Compiled from "Test.java"
public class com.jyds.Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #9.#18         //  java/lang/Object."<init>":()V
   #2 = String             #19            //  1
   #3 = String             #20            //  2
   #4 = Class              #21            //  java/lang/StringBuilder
   #5 = Methodref          #4.#18         //  java/lang/StringBuilder."<init>":()V
   #6 = Methodref          #4.#22         //  java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #7 = Methodref          #4.#23         //  java/lang/StringBuilder.toString:()Ljava/lang/String;
   #8 = Class              #24            //  com/jyds/Test
   #9 = Class              #25            //  java/lang/Object
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               SourceFile
  #17 = Utf8               Test.java
  #18 = NameAndType        #10:#11        //  "<init>":()V
  #19 = Utf8               1
  #20 = Utf8               2
  #21 = Utf8               java/lang/StringBuilder
  #22 = NameAndType        #26:#27        //  append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #23 = NameAndType        #28:#29        //  toString:()Ljava/lang/String;
  #24 = Utf8               com/jyds/Test
  #25 = Utf8               java/lang/Object
  #26 = Utf8               append
  #27 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #28 = Utf8               toString
  #29 = Utf8               ()Ljava/lang/String;
{
  public com.jyds.Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 6: 0

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: ldc           #2                  // String 1
         2: astore_1      
         3: ldc           #3                  // String 2
         5: astore_2      
         6: new           #4                  // class java/lang/StringBuilder
         9: dup           
        10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
        13: aload_1       
        14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        17: aload_2       
        18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: astore_3      
        25: return        
      LineNumberTable:
        line 8: 0
        line 9: 3
        line 10: 6
        line 11: 25
}
           

上述位元組碼指令解釋

ldc  将int, float或String型常量值從常量池中推送至棧頂
astore_1 将棧頂引用型數值存入第二個本地變量
invokevirtual 調用虛方法,具體實作在運作時會去判斷的

           

從位元組碼可以看出上述代碼是沒有new String對象的(隻new了一次StringBuilder,并可以看出編譯器将"+"操作優化為StringBuilder.append了),沒有new String對象是因為沒有顯示的new String(),這些值在位元組碼的常量池中可以找到,運作時會被直接儲存到本地變量區(由astore指令可以看出)。