深入Class文件结构

2016/4/14 posted in  深入分析Java Web技术内幕
public class Message {
    public static void main(String[] args) {
        System.out.printf("junshan say:Hello Word!");
    }
}


Oolong的语法结构中以“.”符号开头表示这是一个基本的属性项,它对应到Java中就是表示一个Java的基本概念,如一个类、一个方法、一个属性、一个对象或者一个接口等。

类相关的指令

.source Message.java表示这个代码的源文件是Message.java

.class public Message表示这是一个类且公有的类名是Message

.super java/lang/Object表示这个类的父类是Object

方法的定义

.method public <init> ()V表示这是一个公有方法,没有参数,返回值类型是V(也就是void),<init>表示是构造函数

下面的.method public static main([Ljava/lang/String;)V表示的是main方法,它的参数是一个String类型的数组,其中[表示的是数组,而L表示的是一个类形式而不是基本数据类型,凡是L表示的类后面都会以;结尾,表示这个类的结束。

常量池

class文件中的常量池如下:



每个常量都是由三个字节来描述的。

第一个字节表示这个常量是什么类型的常量,JVM定义了12种类型的常量,每个种类的常量都会对应一个数值。

这些常量通常都是相互引用的,是一个常量引用了另一个常量。

UTF8常量类型

它可以存储多个字节长度的字符串值,如可以存储类名或者方法名等很长的一个字符串。

UTF8类型的常量由前两个字节来表示后面所存储的字符串的总字节数

01003c其中的3c表示后面所跟的字节长度有60个。

UTF8常量由三部分表示,包括这个常量是什么格式的,这个常量有多少个字节,后面就是这个常量实际的内容。

Fieldred、Methodref常量类型

为了描述Class中的属性项和方法。

0900100011 Fieldref类型常量

  • 前一个字节表示这个常量是Fieldref类型,所以是09
  • 后面两个字节表示的是该Fieldref是哪个类中的Field,存储的值是第几个常量的位置
  • 后面两个字节表示的是这个Fieldref常量的Name和Type,同样它也是指向NameAndType类型常量的索引

Class常量类型

Class常量表示的是该类的名称,它会指向另外一个UTF8类型的常量,该常量存储的是该类的具体名称

07表示的是Class类型的常量,后面的两个字节表示的是19个常量,而第19个常量正是一个UTF8类型的常量,该常量存储的是java/lang/Object,也就是该类的名称。

NameAndType常量类型

为了表示Methodref和Fieldref的名称和类型描述做进一步说明而存在的,名称通常又由UTF8常量类型来表示,而类型描述也由UTF8来表示,所以NameAndType类型是由一个字节的类型表示加上两个字节的UTF8的位置索引组成的。

  • 0007指向的是第7个常量,表示的是这个Methodref或者Fieldref的名称
  • 0008表示的是Methodref的返回类型或者Fieldref的参数类型

类信息

常量列表的后面就是关于这个类本身的信息描述了,如这个类的访问控制、名称和类型,以及是否有父类或者实现了某些接口等描述信息。

由两个字节表示这个类的访问控制描述

类访问控制的两个字节中实际上只使用了5个bit,其他的bit还没有定义,这5个bit中第一个bit表示的是该类是否是public的,为1的话就是public类,否则就是private类。所以对类的访问修饰只有两种,要么是public要么是private。

第5个bit表示的是该类是否是final类,1表示是,0表示否。

第6个bit描述该类是否含有invokespecial,也就是是否继承其他类,在Java中所有的类默认都继承了Object类。

第10个bit描述了该类是否是接口类,0表示不是接口类,1是接口类。

第12个bit表示该类是否是抽象类,0表示不是抽象类,1表示是抽象类。

后面两个字节0006是该类的类名称,它指向的是第6个常量,0004表示的是该父类的类名称,它指向的是第4个常量定义的名称,再后面的0000表示该类没有实现接口类。