深入理解Java虚拟机 类加载子系统1

Class文件结构

在加类加载子系统之前,我们需要首先了解Class文件的内部结构。
Class文件是一种平台无关的二进制字节码格式(ByteCode),该字节码能够被JVM识别并解释执行或被JVM进一步编译成本地机器码(Native Code)后执行。Class文件以8位字节为单位,排列紧凑中间没有任何分隔符。
Class文件结构

ClassFile {
    //魔数 固定位0xcafebabe
    u4              magic;
    //Class文件版本号和JDK版本
    u2              minor_version;
    u2              major_version;
    //常量池
    u2              constant_pool_count;
    cp_info         contant_pool[constant_pool_count – 1];
    //访问标记
    u2              access_flags;
    //类的继承关系
    u2              this_class;
    u2              super_class;
    //实现的接口
    u2              interfaces_count;
    u2              interfaces[interfaces_count];
    //字段表集合
    u2              fields_count;
    field_info      fields[fields_count];
    //方法表集合
    u2              methods_count;
    method_info     methods[methods_count];

    u2              attributes_count;
    attribute_info  attributes[attributes_count];
}



常量池

常量池主要存放字面量(Literal)符号引用(Symbolic Reference)
字面量如:文本字符串(如:String “abc”)、声明为final的常量值。
符号引用如:

  • 类和接口的权限定名(如: “java.lang.Object”)
  • 字段的名称和描述符
  • 方法的名称和描述符

Java编译和C/C++不同,没有链接Linking步骤,编译后的Class文件中只是方法和字段的符号引用,而没有真正内存地址。当虚拟机运行时需要从常量池获取对应符号引用,在类加载的才将符号引用翻译成具体地址;甚至在方法多态情况下在每次方法执行时才翻译为具体地址。

常量池项目类型主要有

CONSTANT_Utf8_info     方法、字段等都需要用该类型常量描述
CONSTANT_String_info    字符串类型字面量
CONSTANT_FieldRef_info    字段符号引用
CONSTANT_MethodRef_info    类中方法符号引用
CONSTANT_Class_info    类或接口引用符号(类全限定名)

例子如下:
http://blog.jamesdbloom.com/JVMInternals.html#constant_pool

package org.jvminternals;

public class SimpleClass {
    public void sayHello() {
        System.out.println("Hello");
    }

}

对应常量池:

public class org.jvminternals.SimpleClass
  SourceFile: "SimpleClass.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#17         //  java/lang/Object."<init>":()V
   #2 = Fieldref           #18.#19        //  java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #20            //  "Hello"
   #4 = Methodref          #21.#22        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #23            //  org/jvminternals/SimpleClass
   #6 = Class              #24            //  java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lorg/jvminternals/SimpleClass;
  #14 = Utf8               sayHello
  #15 = Utf8               SourceFile
  #16 = Utf8               SimpleClass.java
  #17 = NameAndType        #7:#8          //  "<init>":()V
  #18 = Class              #25            //  java/lang/System
  #19 = NameAndType        #26:#27        //  out:Ljava/io/PrintStream;
  #20 = Utf8               Hello
  #21 = Class              #28            //  java/io/PrintStream
  #22 = NameAndType        #29:#30        //  println:(Ljava/lang/String;)V
  #23 = Utf8               org/jvminternals/SimpleClass
  #24 = Utf8               java/lang/Object
  #25 = Utf8               java/lang/System
  #26 = Utf8               out
  #27 = Utf8               Ljava/io/PrintStream;
  #28 = Utf8               java/io/PrintStream
  #29 = Utf8               println
  #30 = Utf8               (Ljava/lang/String;)V


访问标志

标示访问信息:是类还是接口?是否为public类型?是否定义abstract?

类索引、父类索引、实现的接口索引
this_class: 在例子中是常量池偏移5,最终指向本类权限定名常量:org/jvminternals/SimpleClass
supr_class:父类,同理。本例:java/lang/Object
interfaces[interfaces_count]:接口同理,只不过Java支持实现多接口。

字段表集合:类变量或者实例变量。

方法表集合
这里写图片描述

属性表集合
属性表集合中最重要的部分就是Code属性,用于java代码编译后的字节码指令。
Code属性如下:

这里写图片描述

上面例子,编译后的字节码:

{
  public org.jvminternals.SimpleClass();
    Signature: ()V
    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

  public void sayHello();
    Signature: ()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 "Hello"
        5: invokevirtual  #4    // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        8: return
 }

参考:
推荐文章http://blog.jamesdbloom.com/JVMInternals.html#constant_pool

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值