JVM篇【Java源文件和Class字节码文件对比】

简介: JVM篇【Java源文件和Class字节码文件对比】

在分析JVM相关知识之前,给大家分享一段代码,非常通俗易懂的代码。

代码如下:

package com.test.util;
import java.io.Serializable;
public class Test implements Serializable {
    private static String name = "JVM";
    public static void main(String[] args) {
        System.out.println(name);
    }
}

我们逐个分析,首先我们有一个Test.java的源文件,源文件名称就是我们Class文件属性表中的SourceFile属性。(这个需要结合Class字节码文件结构来看)


字节码结构有:魔数,副版本号,主版本号,常量池容量计数器,访问标志,类索引,父类索引,接口索引集合,字段表,方法表,属性表等。


拿魔数来说,它是用来区分文件类型的一种标志,会占用开头的4个字节,之所以需要魔数来区分文件类型,是因为文件名后缀容易被修改,所以为了保证文件的安全性,将文件类型写在文件内部可以保证不被篡改。


魔数后面的4位就是版本号,也是4个字节,前2个字节表示次版本号,后2个字节表示主版本号,这二个版本号是为了标注jdk的一个版本,起到一个jdk版本兼容性的一个作用,比如说高版本的jdk代码不能使用低版本的jdk运行,这个时候主次版本号就起到这个作用。


版本号后二个字节就是常量池容量计数器,写代码时都是从0开始的,但是这里的常量池却是从1开始,因为它把第0项常量空出来了,这是为了满足不引用任何一个常量池的项目,比如说匿名内部类,它没有类名,但是它的类名也需要存储到常量池里面,那只能指向常量池的第0号位置,又比如说Object类,它是所有类的父类,那它的父类指向的是常量池中的0的位置。


常量池后面就是访问标志,用两个字节来表示,其标识了类或者接口的访问信息,比如:这个.Class文件是类还是接口,是不是被定义成public,是不是abstract,如果是类,是不是被声明成final等。


访问标志后的两个字节就是类索引,通过类索引我们可以确定到类的全限定名。类索引后的两个字节就是父类索引,通过父类索引可以确定到父类的全限定名,通过这二个全限定名可以获取到类路径。


父类索引后的两个字节是接口索引计数器,接口索引计数器表示接口索引集合中接口的数量。


接口索引计数器后边二个字节是接口索引集合,它是按照当前类实现的接口顺序,从左到右依次排列在接口索引集合中。


接口索引集合后边二个字节是字段表计数器,用来表示字段表的容量,字段表计数器后边是字段表。我们知道,一个字段可以被各种关键字去修饰,比如:作用域修饰符(public、private、protected)、static修饰符、final修饰符、volatile修饰符等,所以也可以像类的访问标志那样,使用一些标识来标记字段。


字段表作为一个表,同样他也有自己的结构,比如说访问标志,字段名索引,描述符索引,属性计数器,属性集合。在Java语言中字段是无法重载的,两个字段的数据类型,修饰符不管是否相同,都必须要有不一样的名称,但是对于字节码文件来说,如果两个字段的描述符不一致,那这二个字段重名就是合法的。


字段表后边二个字节是方法表计数器,表示方法表的容量,方法表计数器后边紧跟的是方法表。和字段表类似,方法表里面也有自己的结构,比如说访问标志,方法名索引,描述符索引,属性计数器,属性集合。


方法表后边紧跟的是属性表计数器,属性表计数器后边紧跟的结构为属性表。属性表的两大特点:一个是限制比较宽松,没有顺序长度要求;一个是开发者可以根据自己的需求,向属性表中添加不重复的属性。通过上面一大堆的讲解,可以发现Class文件结构是以魔数开头,以属性表结尾的。


然后我们看代码的第一行,package com.test.util;这个package就是存放在常量池里面的。


接着看第二行,import java.io.Serializable;这个import后面的全限定名也是存放在常量池里面的。


接着分析第三行public class Test implements Serializable {

public表示的是访问标志

class表示的是类索引

Test表示的是类名称,存放在常量池里面

implements表示的是接口索引集合

Serializable表示的是接口名称,存放在常量池里面


接着分析第四行 private static String name = “JVM”;

private表示的是常量修饰符

static表示的是常量修饰符

String是字段表,索引指向常量池

name是字段名称,存放在常量池里面

以上这行代码没有用final修饰,在clinit中初始化


分析第五行public static void main(String[] args) {

public是方法修饰符

static方法修饰符

void方法表,索引指向常量池

main方法名,存放在常量池

String[]方法表

args方法表中的属性表中的MethodParameters


最后第六行System.out.println(name);这行表示方法代码,是方法表中的属性表中的Code属性


最后我们我们代码左边的行数在class文件中是属性表的LineNumberTable属性


相关文章
|
6天前
|
Oracle Java 关系型数据库
JVM(一)-JVM与Java体系结构
JVM(一)-JVM与Java体系结构
12 2
|
7天前
|
安全 Java 编译器
Java 虚拟机加载 Java 类的过程
【6月更文挑战第7天】Java 是一门编译型语言,在完成代码的编写以后,需要使用 Java 编译器将源码编译成字节码文件,供虚拟机运行。在字节码被 Java 虚拟机执行之前,需要将对应的类进行加载。
36 3
|
6天前
|
前端开发 JavaScript Java
Java基础10-深入理解Class类和Object类(二)
Java基础10-深入理解Class类和Object类(二)
15 5
|
6天前
|
Java C++
Java基础10-深入理解Class类和Object类(一)
Java基础10-深入理解Class类和Object类(一)
14 4
|
6天前
|
Java 编译器 开发者
Java基础3-JVM层面理解Java继承、封装、多态的实现原理(二)
Java基础3-JVM层面理解Java继承、封装、多态的实现原理(二)
7 0
|
6天前
|
存储 Java 索引
Java基础3-JVM层面理解Java继承、封装、多态的实现原理(一)
Java基础3-JVM层面理解Java继承、封装、多态的实现原理(一)
12 0
|
6天前
|
存储 XML 安全
JVM系列5-类文件结构
JVM系列5-类文件结构
6 0
|
18天前
|
存储 安全 Java
深入探究Java虚拟机(JVM)的技术细节
深入探究Java虚拟机(JVM)的技术细节
|
19天前
|
IDE Java Unix
Java的class path的设置与应用
Java的class path的设置与应用
|
19天前
|
存储 算法 Java
深入理解Java虚拟机(JVM)的垃圾回收机制
【5月更文挑战第30天】 在Java开发领域,垃圾回收(Garbage Collection, GC)是确保应用程序性能和内存效率的关键因素。本文将深入探讨Java虚拟机(JVM)的垃圾回收机制,解析其工作原理、不同算法的特点以及如何通过调优来提高应用性能。我们将透过JVM的内存结构,探索垃圾回收过程中涉及的关键技术点,并讨论现代Java应用中常见的垃圾回收器实现。