【JVM】類(lèi)文件結(jié)構(gòu)

Class文件是一組以8位字節(jié)為基礎(chǔ)單位的二進(jìn)制流,各個(gè)數(shù)據(jù)項(xiàng)目按照順序緊湊地排列在Class文件中,中間沒(méi)有任何分隔符。

使用命令javac將.java 文件編譯為.class文件
使用命令javap輸出.class文件的字節(jié)碼內(nèi)容

Class文件格式采用類(lèi)似于C語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu),只有兩種數(shù)據(jù)類(lèi)型:無(wú)符號(hào)數(shù)和表。

  • 無(wú)符號(hào)數(shù):屬于基本的數(shù)據(jù)類(lèi)型,以u(píng)1、u2、u4、u8分別代表1個(gè)字節(jié)、2個(gè)字節(jié)、4個(gè)字節(jié)、8個(gè)字節(jié)的無(wú)符號(hào)數(shù)。無(wú)符號(hào)數(shù)用來(lái)描述數(shù)字、索引引用、數(shù)量值或者按照UTF-8編碼構(gòu)成字符串值。
  • :由多個(gè)無(wú)符號(hào)數(shù)或其他表作為數(shù)據(jù)項(xiàng)構(gòu)成的復(fù)合數(shù)據(jù)類(lèi)型。所有表都以_info結(jié)尾。表用于描述有層次關(guān)系的復(fù)合結(jié)構(gòu)的數(shù)據(jù),整個(gè)Class文件本質(zhì)上就是一張表,由下表中的數(shù)據(jù)項(xiàng)構(gòu)成。
名稱 類(lèi)型 數(shù)量
magic u4 1
minor_version u2 1
major_version u2 1
constant_pool_count u2 1
constant_pool cp_info constant_pool_count - 1
access_flags u2 1
this_class u2 1
super_class u2 1
interfaces_count u2 1
interfaces u2 interfaces_count
fields_count u2 1
fields field_info fields_count
methods_count u2 1
methods method_info methods_count
attributes_count u2 1
attributes attribute_info attributes_count

學(xué)習(xí)類(lèi)文件結(jié)構(gòu),就是要明白上表中各個(gè)數(shù)據(jù)項(xiàng)的具體含義。


魔數(shù)與Class文件版本

  • 魔數(shù)

  • 即上表中的magic,4個(gè)字節(jié),在Class文件的開(kāi)頭。

  • 作用是確定該文件是否為一個(gè)被虛擬機(jī)接受的Class文件。使用魔數(shù)而不是后綴名的方式是基于安全的考慮:文件擴(kuò)展名可以任意更改。

  • 正常的Class文件的魔數(shù)為0xCAFEBABE。cafe babe ,咖啡寶貝。

    Java.png

  • 版本號(hào)

  • 即上表中的major_versionminor_version:Class文件的第5、6個(gè)字節(jié)是次版本號(hào)minor_version,第7、8個(gè)字節(jié)是主版本號(hào)major_version。

  • 高版本的JDK可以向下兼容,但低版本的JDK不向上兼容,虛擬機(jī)會(huì)拒絕執(zhí)行。


常量池

常量池是Class文件中的資源倉(cāng)庫(kù),它是Class文件結(jié)構(gòu)中與其他數(shù)據(jù)項(xiàng)關(guān)聯(lián)最多的數(shù)據(jù)類(lèi)型,也是占用Class文件空間最大的數(shù)據(jù)項(xiàng)之一。

  • 常量池容器計(jì)數(shù)值

  • 即上表中的constant_pool_count,2個(gè)字節(jié)

  • 常量池中的常量的數(shù)量是不固定的,所以需要constant_pool_count來(lái)表示常量池中常量的數(shù)量。

  • 該容器計(jì)數(shù)從1開(kāi)始(而不是Java語(yǔ)言習(xí)慣中從0開(kāi)始),比如constant_pool_count的值為16,則說(shuō)明常量池中有15項(xiàng)常量,索引值范圍為1-15。將第0項(xiàng)常量空出來(lái)的目的是為了滿足后面某些指向常量池的索引值的數(shù)據(jù)在特定情況下表達(dá)“不引用任何一個(gè)常量池項(xiàng)”的含義。

  • 常量池

  • 從概念上理解,常量池 = constant_pool[constant_pool_count - 1]。

  • 常量池中主要存放兩大類(lèi)常量:字面量和符號(hào)引用。
    ①字面量:接近于Java語(yǔ)言層面的常量概念,如文本字符串、聲明為final的常量值等。
    ②符號(hào)引用:屬于編譯原理方面的概念,主要包括:類(lèi)和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符。Java代碼在經(jīng)過(guò)javac命令編譯之后,生成的Class文件中并不會(huì)保存各個(gè)方法、字段的最終內(nèi)存布局信息,必須等到虛擬機(jī)運(yùn)行時(shí),從常量池中獲得對(duì)應(yīng)的符號(hào)引用,再通過(guò)這些符號(hào)引用經(jīng)過(guò)類(lèi)創(chuàng)建或運(yùn)行時(shí)解析、翻譯等才能得到具體的內(nèi)存地址。

  • 常量池中共有14中類(lèi)型的常量,每一個(gè)常量(項(xiàng))都有自己的表結(jié)構(gòu),但這14種表的有一個(gè)共同特點(diǎn):表開(kāi)始的第一位是一個(gè)u1類(lèi)型的標(biāo)志位tag,代表這個(gè)常量屬于哪種常量類(lèi)型。常量池中的常量類(lèi)型見(jiàn)下表。

常量類(lèi)型 表類(lèi)型 tag取值
UTF-8編碼的字符串 CANSTANT_Utf8_info 1
整型字面量 CANSTANT_Integer_info 3
浮點(diǎn)型字面量 CANSTANT_Float_info 4
長(zhǎng)整型字面量 CANSTANT_Long_info 5
雙精度浮點(diǎn)型字面量 CANSTANT_Double_info 6
類(lèi)或接口的符號(hào)引用 CANSTANT_Class_info 7
字符串類(lèi)型字面量 CANSTANT_String_info 8
字段的符號(hào)引用 CANSTANT_Fieldref_info 9
類(lèi)中方法的符號(hào)引用 CANSTANT_Methodref_info 10
接口中方法的符號(hào)引用 CANSTANT_IntefaceMethodref_info 11
字段或方法的部分符號(hào)引用 CANSTANT_NameAndType_info 12
方法句柄 CANSTANT_MethodHandle_info 15
方法類(lèi)型 CANSTANT_MethodType_info 16
動(dòng)態(tài)方法調(diào)用點(diǎn) CANSTANT_InvokeDynamic_info 18

訪問(wèn)標(biāo)志

即Class文件數(shù)據(jù)項(xiàng)表中的access_flags,用于識(shí)別類(lèi)或者接口層次的訪問(wèn)信息:該是類(lèi)還是接口,是否為public,是否定義為abstract;如果是類(lèi),是否聲明為final;該類(lèi)是否由用戶代碼產(chǎn)生,是否為注解,是否為枚舉等信息。


類(lèi)索引、父類(lèi)索引和接口索引

Class文件根據(jù)這三項(xiàng)數(shù)據(jù)來(lái)確定這個(gè)類(lèi)的繼承關(guān)系。

  • 類(lèi)索引
    即Class文件數(shù)據(jù)項(xiàng)表中的this_class:用于確定這個(gè)類(lèi)的全限定名。
  • 父索引
    即Class文件數(shù)據(jù)項(xiàng)表中的super_class:用于確定這個(gè)類(lèi)的父類(lèi)的全限定名。由于Java是單繼承,只有一個(gè)父類(lèi)。所有類(lèi)(除了java.lang.Object)都有父類(lèi)。
  • 接口索引
    即Class文件數(shù)據(jù)項(xiàng)表中的interfaces_countinterfacesinterfaces_count表示接口索引表的容量,如果該值為0,接口索引表不占用任何字節(jié)。

其中,類(lèi)索引和父索引各自指向一個(gè)常量池中的類(lèi)型為CANSTANT_Class_info的常量,通過(guò)該常量的索引值再定位到常量池中的CANSTANT_Utf8_info類(lèi)型的常量表示的全限定名字符串。


字段表集合

從概念上理解,字段表集合 = fields[fields_count],用于描述該Class文件對(duì)應(yīng)的代碼中聲明的變量:包括類(lèi)級(jí)變量以及實(shí)例變量,但不包括方法內(nèi)聲明的局部變量。
對(duì)于一個(gè)字段,描述信息主要有:作用域(public、private、protected),是實(shí)例變量還是類(lèi)變量(有無(wú)static修飾),可變性(final),并發(fā)可見(jiàn)性(volatile),可否被序列化(transient),數(shù)據(jù)類(lèi)型(基本類(lèi)型、對(duì)象、數(shù)組),名稱。這些信息中各個(gè)修飾符都是布爾值(要么有,要么沒(méi)有),用標(biāo)志位表示,而名稱、數(shù)據(jù)類(lèi)型則引用常量池中的常量來(lái)描述。
每一個(gè)字段會(huì)對(duì)應(yīng)一個(gè)字段表,字段表的最終結(jié)構(gòu)如下。

名稱 類(lèi)型 數(shù)量
access_flag u2 1
name_index u2 1
descriptor_index u2 1
attributes_count u2 1
attributes attribute_info attributes_count
  • access_flag
    該字段的修飾符信息:是否public、private、protected、static、final、volatile、transient、enum等。
  • name_index
    該字段的簡(jiǎn)單名稱,是對(duì)常量池的常量引用。比如在代碼中定義private String name,則name字段的簡(jiǎn)單名稱就是name,但是這個(gè)name這個(gè)字面量是在常量池中的,name_index存儲(chǔ)的是對(duì)常量池中該常量項(xiàng)的引用。
  • descriptor_index
    該字段的描述符,描述字段的數(shù)據(jù)類(lèi)型。
  • attributes和attributes
    該字段的屬性表,見(jiàn)下文。

字段表集合中不會(huì)列出從超類(lèi)或父接口中繼承而來(lái)的字段,但有可能會(huì)列出原本Java代碼中不存在的字段,比如在內(nèi)部類(lèi)中為了保持對(duì)外類(lèi)的訪問(wèn)性,在編譯Class文件的時(shí)候會(huì)自動(dòng)添加外部類(lèi)的實(shí)例字段。


方法表集合

從概念上理解,方法表集合 = methods[methods_count]。每一個(gè)方法對(duì)應(yīng)一個(gè)方法表method_info。方法表與字段表的結(jié)構(gòu)一致,只是具體的信息項(xiàng)不同。

名稱 類(lèi)型 數(shù)量
access_flag u2 1
name_index u2 1
descriptor_index u2 1
attributes_count u2 1
attributes attribute_info attributes_count

其中,訪問(wèn)信息access_flag包括是否public、private、protected、static、final、synchronized、native、abstract、strictfp、是否接受不定參數(shù)、是否由編譯器自動(dòng)產(chǎn)生等。
其中,方法描述符descriptor_index中描述了方法的參數(shù)列表(數(shù)量、類(lèi)型、順序)和返回值。

而方法體中的代碼,經(jīng)過(guò)編譯器編譯成字節(jié)碼指令后,存儲(chǔ)在方法屬性表attributes[attributes_count]中。

如果子類(lèi)沒(méi)有重寫(xiě)父類(lèi)的方法,則子類(lèi)的方法表集合中不會(huì)出現(xiàn)來(lái)自父類(lèi)的方法信息,但可能會(huì)出現(xiàn)編譯器自動(dòng)添加的方法,如類(lèi)構(gòu)造器<clinit>方法和實(shí)例構(gòu)造器<init>方法。


屬性表集合

在Class文件、字段表、方法表中都可以包含自己的屬性表集合,以此描述某些場(chǎng)景專(zhuān)有的信息。

1、Code屬性

Java程序方法體中的代碼經(jīng)過(guò)javac編譯器編譯之后,最終變?yōu)樽止?jié)碼指令存儲(chǔ)在Code屬性表中,即Code屬性表是方法表的一部分。但并非所有的方法表都存在該屬性,比如接口或者抽象類(lèi)中的抽象方法就不存在Code屬性表。Code屬性表的結(jié)構(gòu)如下。

名稱 類(lèi)型 數(shù)量
attribute_name_index u2 1
attribute_length u4 1
max_stack u2 1
max_locals u2 1
code_length u4 1
code u1 code_length
exception_table_length u2 1
exception_table exception_info exception_length
attributes_count u2 1
attributes attribute_info attributes_count
  • attribute_name_index和attribute_length
    attribute_name_index表示該屬性表的名稱,即Code,是指向常量池中類(lèi)型為CANSTANT_Utf8_info的常量的索引。
    attribute_length表示該屬性值的長(zhǎng)度。

  • max_stack
    代表了操作數(shù)棧深度的最大值。在方法執(zhí)行的任意時(shí)刻,操作數(shù)棧都不會(huì)超過(guò)這個(gè)深度。虛擬機(jī)運(yùn)行的時(shí)候需要根據(jù)這個(gè)值來(lái)分配幀棧中的操作深度。

  • max_locals
    代表了局部變量表所需要的存儲(chǔ)空間。max_locals的單位是Slot,Slot是虛擬機(jī)為局部變量分配內(nèi)存所使用的最小單位。對(duì)于byte、char、float、int、short、boolean、returnAddress等長(zhǎng)度不超過(guò)32位的數(shù)據(jù)類(lèi)型,每個(gè)局部變量占用一個(gè)Slot,double和long這兩種64位的數(shù)據(jù)類(lèi)型則需要兩個(gè)Slot。方法參數(shù)(包括實(shí)例方法中的隱藏參數(shù)this)、顯式異常處理器的參數(shù)(try-catch中catch塊所定義的異常)、方法體中定義的局部變量都需要使用局部變量表來(lái)存放。局部變量表中的Slot可以重用,當(dāng)代碼執(zhí)行超過(guò)一個(gè)局部變量的作用域時(shí),這個(gè)局部變量所占用的Slot可以被其他局部變量所使用。Javac編譯器會(huì)根據(jù)變量的作用域來(lái)分配Slot給各個(gè)變量使用,然后計(jì)算出max_locals的大小。

  • code_length和code

  • code_length代表字節(jié)碼長(zhǎng)度,即字節(jié)碼指令的個(gè)數(shù),也就是code的長(zhǎng)度。雖然是u4類(lèi)型(2^32),但虛擬機(jī)規(guī)范中明確規(guī)定一個(gè)方法不允許超過(guò)65535條字節(jié)碼指令,即它只使用了u2的長(zhǎng)度,超過(guò)這個(gè)長(zhǎng)度,Javac編譯器會(huì)拒絕編譯。

  • code中存儲(chǔ)的是字節(jié)碼指令的一系列字節(jié)流。對(duì)于字節(jié)碼指令,每個(gè)指令都是單字節(jié)(u1類(lèi)型)。當(dāng)虛擬機(jī)讀取到code中的一個(gè)字節(jié)碼時(shí),就可以找出對(duì)應(yīng)的這個(gè)字節(jié)碼對(duì)應(yīng)的指令,并且可以知道這個(gè)指令后面是否需要跟隨參數(shù)以及參數(shù)應(yīng)當(dāng)如何理解。因?yàn)樽止?jié)碼指令是用1個(gè)字節(jié)(8位,2^8=256)來(lái)表示,所以一共可以表示256條指令。目前,Java虛擬機(jī)規(guī)范已經(jīng)定義了其中約200條編碼值對(duì)應(yīng)的指令含義。

  • exception_table_length和exception_table
    顯式異常處理表集合,對(duì)于Code屬性來(lái)說(shuō)并不是必須的,表示的是try-catch中的異常信息描述。

Code屬性是Class文件中最重要的一個(gè)屬性,如果把一個(gè)Java程序的信息分為代碼和元數(shù)據(jù)兩部分,那么在整個(gè)Class文件中,Code屬性用于描述代碼,所有的其他數(shù)據(jù)項(xiàng)目都用于描述元數(shù)據(jù)。

2、Exceptions屬性

屬于方法表中的一部分。作用是列出出方法中可能拋出的受檢查異常,也就是方法描述時(shí)在throws 關(guān)鍵字后面列出的異常。

3、LineNumberTable屬性

屬于Code屬性的一部分。用于描述Java源代碼行號(hào)與字節(jié)碼行號(hào)之間的對(duì)應(yīng)關(guān)系,它并不是運(yùn)行時(shí)必須的屬性,默認(rèn)生成,可以在javac命令中使用 -g:none-g:lines屬性取消生成該信息。不生成該信息對(duì)程序運(yùn)行的影響:當(dāng)拋出異常時(shí),堆棧中將不會(huì)顯示出錯(cuò)的行號(hào),并且在調(diào)試程序的時(shí)候,也無(wú)法按照源碼行來(lái)設(shè)置斷點(diǎn)。

4、LocalVariableTable屬性

屬于Code屬性的一部分。用于描述幀棧中局部變量表中的變量與Java源代碼定義的變量之間的關(guān)系,不是運(yùn)行時(shí)必須的屬性,默認(rèn)生成,可以在javac命令中使用 -g:none-g:vars屬性取消生成該信息。不生成該信息的影響:當(dāng)其他人引用該方法時(shí),所有的參數(shù)名稱都會(huì)丟失,IDE會(huì)使用類(lèi)似arg0、arg1等占位符代替原有的參數(shù)名,給代碼編寫(xiě)帶來(lái)不便。

5、ConstantValue屬性

屬于字段表中的一部分。作用是通知虛擬機(jī)自動(dòng)為靜態(tài)變量賦值,只有被static關(guān)鍵字修飾的變量(類(lèi)變量)才可以使用該屬性。虛擬機(jī)對(duì)類(lèi)變量和實(shí)例變量的賦值方式和時(shí)機(jī)有所不同。對(duì)于實(shí)例變量的賦值是在實(shí)例構(gòu)造器<init>方法中進(jìn)行的。對(duì)于類(lèi)變量,如果是同時(shí)有static和final修飾的基本類(lèi)型數(shù)據(jù)或String類(lèi)型數(shù)據(jù),則會(huì)生成ConstantValue屬性來(lái)進(jìn)行初始化,否則在<clinit>方法中進(jìn)行初始化。


實(shí)例分析

定義一個(gè)父類(lèi)Animal,兩個(gè)接口Eat、Sleep,一個(gè)要分析的Rabbit類(lèi)。

package constructor;
public class Animal {

    protected String weight;

    public String getWeight() {
        return weight;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }
}
package constructor;
public interface Sleep {
    void sleep();
}
package constructor;
public interface Eat {
    void eat();
}
package constructor;
public class Rabbit extends Animal implements Eat, Sleep{

    private String nickName;

    private int age;

    public static final boolean isCute = true;

    @Override
    public void eat() {
        System.out.println("I eat grass");
    }

    @Override
    public void sleep() {
        System.out.println("I sleep well");
    }

    public String play(int temperature){
        if(temperature > 10){
            return "I want to play outside";
        }else {
            return "I want to stay at home";
        }
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

使用命令javac *.java編譯所有源文件,生成class文件。(如果僅僅單獨(dú)編譯Rabbit.java文件會(huì)提示找不到類(lèi)Sleep、Eat和Animal等)。
使用javap -verbose Rabbit.class命令查看Rabbit.class文件的字節(jié)碼內(nèi)容。

Classfile /Users/yue/Documents/workspace/idea/datacenter/src/test/constructor/Rabbit.class
  Last modified 2017-7-9; size 1092 bytes
  MD5 checksum 64e6283bb3c70e9c41fb2f72e09aae13
  Compiled from "Rabbit.java"
public class constructor.Rabbit extends constructor.Animal implements constructor.Eat,constructor.Sleep
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #11.#41        // constructor/Animal."<init>":()V
   #2 = Fieldref           #42.#43        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #44            // I eat grass
   #4 = Methodref          #45.#46        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = String             #47            // I sleep well
   #6 = String             #48            // I want to play outside
   #7 = String             #49            // I want to stay at home
   #8 = Fieldref           #10.#50        // constructor/Rabbit.nickName:Ljava/lang/String;
   #9 = Fieldref           #10.#51        // constructor/Rabbit.age:I
  #10 = Class              #52            // constructor/Rabbit
  #11 = Class              #53            // constructor/Animal
  #12 = Class              #54            // constructor/Eat
  #13 = Class              #55            // constructor/Sleep
  #14 = Utf8               nickName
  #15 = Utf8               Ljava/lang/String;
  #16 = Utf8               age
  #17 = Utf8               I
  #18 = Utf8               isCute
  #19 = Utf8               Z
  #20 = Utf8               ConstantValue
  #21 = Integer            1
  #22 = Utf8               <init>
  #23 = Utf8               ()V
  #24 = Utf8               Code
  #25 = Utf8               LineNumberTable
  #26 = Utf8               eat
  #27 = Utf8               sleep
  #28 = Utf8               play
  #29 = Utf8               (I)Ljava/lang/String;
  #30 = Utf8               StackMapTable
  #31 = Utf8               getNickName
  #32 = Utf8               ()Ljava/lang/String;
  #33 = Utf8               setNickName
  #34 = Utf8               (Ljava/lang/String;)V
  #35 = Utf8               getAge
  #36 = Utf8               ()I
  #37 = Utf8               setAge
  #38 = Utf8               (I)V
  #39 = Utf8               SourceFile
  #40 = Utf8               Rabbit.java
  #41 = NameAndType        #22:#23        // "<init>":()V
  #42 = Class              #56            // java/lang/System
  #43 = NameAndType        #57:#58        // out:Ljava/io/PrintStream;
  #44 = Utf8               I eat grass
  #45 = Class              #59            // java/io/PrintStream
  #46 = NameAndType        #60:#34        // println:(Ljava/lang/String;)V
  #47 = Utf8               I sleep well
  #48 = Utf8               I want to play outside
  #49 = Utf8               I want to stay at home
  #50 = NameAndType        #14:#15        // nickName:Ljava/lang/String;
  #51 = NameAndType        #16:#17        // age:I
  #52 = Utf8               constructor/Rabbit
  #53 = Utf8               constructor/Animal
  #54 = Utf8               constructor/Eat
  #55 = Utf8               constructor/Sleep
  #56 = Utf8               java/lang/System
  #57 = Utf8               out
  #58 = Utf8               Ljava/io/PrintStream;
  #59 = Utf8               java/io/PrintStream
  #60 = Utf8               println
{
  public static final boolean isCute;
    descriptor: Z
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: int 1

  public constructor.Rabbit();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method constructor/Animal."<init>":()V
         4: return
      LineNumberTable:
        line 11: 0

  public void eat();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String I eat grass
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 21: 0
        line 22: 8

  public void sleep();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #5                  // String I sleep well
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 26: 0
        line 27: 8

  public java.lang.String play(int);
    descriptor: (I)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: bipush        10
         3: if_icmple     9
         6: ldc           #6                  // String I want to play outside
         8: areturn
         9: ldc           #7                  // String I want to stay at home
        11: areturn
      LineNumberTable:
        line 30: 0
        line 31: 6
        line 33: 9
      StackMapTable: number_of_entries = 1
        frame_type = 9 /* same */

  public java.lang.String getNickName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #8                  // Field nickName:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 38: 0

  public void setNickName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #8                  // Field nickName:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 42: 0
        line 43: 5

  public int getAge();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #9                  // Field age:I
         4: ireturn
      LineNumberTable:
        line 46: 0

  public void setAge(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #9                  // Field age:I
         5: return
      LineNumberTable:
        line 50: 0
        line 51: 5
}
SourceFile: "Rabbit.java"

內(nèi)容摘抄自《深入理解Java虛擬機(jī)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 簡(jiǎn)介 Class文件是Java虛擬機(jī)執(zhí)行引擎的數(shù)據(jù)入口,也是Java技術(shù)體系的基礎(chǔ)構(gòu)成之一。了解Class文件的結(jié)...
    黃俊彬閱讀 319評(píng)論 0 0
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 12,413評(píng)論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,697評(píng)論 18 399
  • 看到這篇文章的你是“小蘑菇”么?是的話,跟你握個(gè)手;不是的話,請(qǐng)受我一拜。 這周五,我的工作情緒是低落的。我是做后...
    阿歷Ali閱讀 573評(píng)論 1 0
  • “他死了?!?“我不回來(lái)?!?01 扶蘇學(xué)會(huì)抽煙那年,她剛滿二十歲。 扶蘇開(kāi)始戒煙那年,剛過(guò)二十五歲。 二十五歲的...
    沈鹿之閱讀 1,065評(píng)論 0 0

友情鏈接更多精彩內(nèi)容