JVM——Class文件

本文详细介绍了Java Class文件的结构,包括魔数、版本号、常量池、访问标志、类索引、父类索引、接口、字段、方法和属性等组成部分。通过对Class文件的解析,我们可以了解到Class文件的每个字段的含义和作用。同时,文章提到了ASM框架,这是一个用于动态生成和修改类的Java字节码操作框架,可用于修改类的行为或分析类信息。
摘要由CSDN通过智能技术生成

简介

C或者C++传统语言写的程序通常首先被编译,然后被连接成单独的、专门支持特定硬件平台和操作系统的二进制文件,因此一个平台上的二进制可执行文件往往不能在其他平台上工作,而Java 程序是先被编译成Class文件,然后通过Classloader装载进入JVM运行时环境的方法区中,直到被字节码执行引擎执行。

写完程序点击运行,编译器会自动将代码编译成class文件然后交给JVM去执行,但是JVM只认Class文件,毫不关心这个Class是如何生成的,只要符合JVM规范中定义的Class文件的结构即可,所以其他语言也可以通过JVM来执行,这就是JVM的语言无关性。

通常我们会认为只有与Java类似的Kotlin、Groovy、Jython等语言能直接编译成Class文件
在这里插入图片描述
但是时至今日,GraalVM的出现已经可以让更多的语言来享受JVM的托管环境,并且能支持的语言也越来越多。
在这里插入图片描述

文件结构

Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,如果遇到需要占用8个字节以上空间的数据项时,会按照高位在前的方式分割成若干个8个字节进行存储。高位在前就是Big-Endian,即按高位字节在地址最低位,最低字节在地址最高位来存储数据。

JVM规范文档中严格规定了Class文件结构,只有满足规范的Class二进制流文件才会被装载到方法区,否则在ClassLoader连接的验证阶段就会被剔除。
JVM中规定的Class文件结构
先看左边一列

  • u1、u2、u4、u8
    这些是无符号数,u1、 u2、 u4、 u8分别代表1个字节、 2个字节、 4个字节和8个字节的无符号数
  • _info结尾
    这些是表,表用于描述有层次关系的复合结构的数据, 整个Class文件本质上也可以视作是一张表

再看右边一列

magic

魔数:很多文件格式标准中都有使用魔数来进行身份识别的习惯, 譬如图片格式, 如GIF或者JPEG等在文件头中都存有魔数,Class文件也不例外,Class文件的魔数是0xCAFEBABE,不能修改,它用来确定这个文件是否为一个能被虚拟机接受的Class文件。

minor_version 和 major_version

minor_version 是副版本号:Java 2出现前被短暂使用过,后来一直被弃用(值固定为0),直到JDK12出现,由于JDK提供的功能集已经非常庞大, 有一些复杂的新特性需要以“公测”的形式放出, 所以设计者重新启用了副版本号, 将它用于标识“技术预览版”功能特性的支持。 如果Class文件中使用了该版本JDK尚未列入正式特性清单中的预览功能, 则必须把次版本号标识为65535, 以便Java虚拟机在加载类文件时能够区分出来。

major_version是主版本号:JDK版本是向下兼容的,它不能执行高于自身版本的Class文件

在这里插入图片描述

constant_pool_count 和 constant_pool[constant_pool_count-1]

constant_pool_count表示常量池里面常量个数,它的值等于常量池中成员数加1
constant_pool[constant_pool_count-1]是常量池,它包含Class文件结构及其子结构中所有字符串常量、类名、接口名、字段名和其他常量

access_flags

访问标志:是一种由标志所构成的掩码,用于表示某个类或者接口的访问权限及属性

this_class

类索引:它的值是常量池中某项的索引

super_class

父类索引,要么是0,要么也是常量池中某项的索引

intertaces_count 和 interfaces[intertaces_count]

intertaces_count是当前类或接口的直接超接口数量
interfaces[intertaces_count]接口表

fields_count 和 fields[fields_count]

fields_count 表示当前class文件fields表的成员个数

methods_count 和 methods[methods_count]

methods_count表示当前class文件methods表的成员个数

attributes_count 和 attributes[attributes_count]

attributes_count 表示当前class文件attributes表的成员个数

了解Class文件具体结构可以看官方文档,或者查看8.0中文文档 提取码:v1fz

实战

首先写一个类

public class Hello{
   
	private static String message = "Hello World!";
	
	static{
   
		System.out.println("class has been loaded");
	}
	
	private int add(int a, int b){
   
		return a + b;
	}
	
	public static void main(String[] args){
   
		System.out.println("Dean say " + message);
	} 
}

通过javac -g:vars Hello.java 编译成class文件,然后使用javap -verbose Hello,就可以简单查看class文件翻译后的样子

Classfile /C:/Users/LWH/Desktop/Hello.class
  Last modified 2021-3-26; size 839 bytes
  MD5 checksum c9a28db4d04a7b597d25b698820b4bbf
public class Hello
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #13.#32        // java/lang/Object."<init>":()V
   #2 = Fieldref           #33.#34        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Class              #35            // java/lang/StringBuilder
   #4 = Methodref          #3.#32         // java/lang/StringBuilder."<init>":()V
   #5 = String             #36            // Dean say
   #6 = Methodref          #3.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #7 = Fieldref           #12.#38        // Hello.message:Ljava/lang/String;
   #8 = Methodref          #3.#39         // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #9 = Methodref          #40.#41        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #10 = String             #42            // Hello World!
  #11 = String             #43            // class has been loaded
  #12 = Class              #44            // Hello
  #13 = Class              #45            // java/lang/Object
  #14 = Utf8               message
  #15 = Utf8               Ljava/lang/String;
  #16 = Utf8               <init>
  #17 = Utf8               ()V
  #18 = Utf8               Code
  #19 = Utf8               LocalVariableTable
  #20 = Utf8               this
  #21 = Utf8               LHello;
  #22 = Utf8               add
  #23 = Utf8               (II)I
  #24 = Utf8               a
  #25 = Utf8               I
  #26 = Utf8               b
  #27 = Utf8               main
  #28 = Utf8               ([Ljava/lang/String;)V
  #29 = Utf8               args
  #30 = Utf8               [Ljava/lang/String;
  #31 = Utf8               <clinit>
  #32 = NameAndType        #16:#17        // "<init>":()V
  #33 = Class              #46            // java/lang/System
  #34 = NameAndType        #47:#48        // out:Ljava/io/PrintStream;
  #35 = Utf8               java/lang/StringBuilder
  #36 = Utf8               Dean say
  #37 = NameAndType        #49:#50        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #38 = NameAndType        #14:#15        // message:Ljava/lang/String;
  #39 = NameAndType        #51:#52        // toString:()Ljava/lang/String;
  #40 = Class              #53            // java/io/PrintStream
  #41 = NameAndType        #54:#55        // println:(Ljava/lang/String;)V
  #42 = Utf8               Hello World!
  #43 = Utf8               class has been loaded
  #44 = Utf8               Hello
  #45 = Utf8               java/lang/Object
  #46 = Utf8               java/lang/System
  #47 = Utf8               out
  #48 = Utf8               Ljava/io/PrintStream;
  #49 = Utf8               append
  #50 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #51 = Utf8               toString
  #52 = Utf8               ()Ljava/lang/String;
  #53 = Utf8               java/io/PrintStream
  #54 = Utf8               println
  #55 = Utf8               (Ljava/lang/String;)V
{
   
  public Hello();
    descriptor: ()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
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LHello;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         0: getstatic     #2                  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值