尚硅谷 宋红康 JVM教程_02_字节码与类的加载篇

本教程深入讲解JVM的字节码与类加载过程,从Class文件结构、字节码指令集到类的加载、链接、初始化等多个方面进行详细介绍,通过实例解析字节码执行细节,帮助理解Java的跨平台性和编译原理。同时,探讨了类加载器的工作机制,包括双亲委派模型及其应用场景,以及自定义类加载器的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列相关链接

尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——01 (20210103-20210110)
https://blog.youkuaiyun.com/wei198621/article/details/112128852

尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——02 (20210111-20210117)
https://blog.youkuaiyun.com/wei198621/article/details/112389917

尚硅谷 宋红康 JVM教程_02_字节码与类的加载篇 (20210118~ )
https://blog.youkuaiyun.com/wei198621/article/details/112760463

todo 3 , 4

目录

尚硅谷 宋红康 JVM教程 学习笔记
https://www.bilibili.com/video/BV1PJ411n7xZ

ppt地址:
https://download.youkuaiyun.com/download/wei198621/14040543

JVM参数列表:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

1.Class文件结构

在这里插入图片描述

P204-JVM中篇内容概述 11:51

https://www.bilibili.com/video/BV1PJ411n7xZ?p=204

1.Class文件结构
2.字节码指令集与解析举例
3.类的加载过程详解
4.再谈类加载器

本节开始用思维导图

中篇开始关注字节码文件,类加载器
在这里插入图片描述在这里插入图片描述
下篇,讲性能监控 、 性能调优
在这里插入图片描述

P205-字节码文件的跨平台性 13:12

第一章_尚硅谷_宋红康_Class文件结构.mmap
在这里插入图片描述在这里插入图片描述java语言跨平台,write once,run anywhere
java虚拟机:跨语言的平台 —Java虚拟机 只与遵循JVM规范的“class文件”关联
docs.oracle.com/javase/specs/index.html

在这里插入图片描述在这里插入图片描述

P206-了解Java的前端编译器 08:30

java 是半解释 半编译型的语言
javac 是一种能够将JAVA源码编译为字节码的前端编译器,是一种全量编译器。
ECJ编译器: Eclipse Compiler for java ,ECJ ,是一种增量式的编译器,Tomcat中使用ECJ编译器编译JSP文件
AOT: Ahead of Time Compiler ,静态提前编译器。
在这里插入图片描述在这里插入图片描述

P207-透过字节码看代码执行细节举例1 11:15

在这里插入图片描述Integer.ValueOf()
Integer Cache : -128~127 ,在这之间的数字,预先加载。

package com.tiza.jvm.chapter21;

/**
 * @author leowei
 * @date 2021/1/18  - 23:33
 */
public class IntegerTest {
   
    public static void main(String[] args) {
   
        m1();
        m2();
        m3();
    }

    /**
     *
     0 bipush 10
     2 invokestatic #5 <java/lang/Integer.valueOf>
     5 astore_0
     6 bipush 10
     8 invokestatic #5 <java/lang/Integer.valueOf>
     11 astore_1
     12 getstatic #6 <java/lang/System.out>
     15 aload_0
     16 aload_1
     17 if_acmpne 24 (+7)
     20 iconst_1
     21 goto 25 (+4)
     24 iconst_0
     25 invokevirtual #7 <java/io/PrintStream.println>
     28 return

     通过查看字节码文件,看到i1  i2 取值的时候会调用valueOf方法,
     如下所示valueOf 方法 会从一个cache 中取数据
     Cache 的值 在 -128~127 之间 
     所以取 -128 ~ 127 之间的数字,不会新建空间,调用cache中的空间就可以了

     * @since  1.5      
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
     
     这解释了  m1  m2  连个问题 

     */
    private static void m1() {
   
        Integer i1=10;
        Integer i2=10;
        System.out.println(i1==i2);  //true
    }


    private static void m2() {
   
        Integer i3=128;
        Integer i4=128;
        System.out.println(i3==i4);   //false
    }

    /**
     *
     0 iconst_5
     1 invokestatic #5 <java/lang/Integer.valueOf>
     4 astore_0
     5 iconst_5
     6 istore_1
     7 getstatic #6 <java/lang/System.out>
     10 aload_0
     11 invokevirtual #8 <java/lang/Integer.intValue>
     14 iload_1
     15 if_icmpne 22 (+7)
     18 iconst_1
     19 goto 23 (+4)
     22 iconst_0
     23 invokevirtual #7 <java/io/PrintStream.println>
     26 return
     此处涉及自动装箱拆箱,暂时没有搞懂此时是装箱还是拆箱  20210118
     */
    private static void m3() {
   
        Integer x=5;
        int y=5;
        System.out.println(x==y);    //true
    }
}

P208-透过字节码看代码执行细节举例2 03:51

package com.tiza.jvm.chapter21;

/**
 * @author leowei
 * @date 2021/1/18  - 23:55
 */
public class StringTest {
   
    public static void main(String[] args) {
   
        // 还是没有搞懂这块,待认真学习 
        m1();
        m2();
        m3();
    }

    private static void m1() {
   
        String str1 =  new String("hello")+new String("world");
        String str2 ="helloworld";
        System.out.println(str1 == str2);  // false      str1  在堆中创建 helloworld     str2 在 stringtable 中 创建 helloworld
    }

    private static void m2() {
   
        String str1 =  new String("helloworld") ;
        String str2 ="helloworld";
        System.out.println(str1 == str2);  // false       str1  在堆中创建 helloworld     str2 在 stringtable 中 创建 helloworld
    }

    private static void m3() {
   
        String str1 =  new String("hello")+new String("world");
        String str2 = new String("helloworld");
        System.out.println(str1 == str2);  // false      str1  在堆中创建 helloworld     str2 在 stringtable 中 创建 helloworld
    }
}

P209-透过字节码看代码执行细节举例3 11:52

20210118 todo

  • 类的非静态成员变量赋值过程
    • 前置1 aload_0 a
    • 前置2 父类初始化
    • step 1 成员变量 默认初始化 x=0
    • step 2 成员变量 显示初始化/代码块中初始化 x=10 后打印
    • step 3 构造器初始化 x=20
    • step 4 (有了对象后) 对象.属性 赋值
package com.tiza.jvm.chapter21;

/**
 *

 0 aload_0                                             0 是this
 1 invokespecial #1 <java/lang/Object.<init>>         调用构造器,首先调用父类的初始化方法
 4 aload_0
 5 bipush 10
 7 putfield #2 <com/tiza/jvm/chapter21/Father.x>       给x赋值 为 10
 10 aload_0
 11 invokevirtual #3 <com/tiza/jvm/chapter21/Father.print>   打印
 14 aload_0
 15 bipush 20
 17 putfield #2 <com/tiza/jvm/chapter21/Father.x>       给x赋值 为 20
 20 return

 */
class Father{
   
    int x=10;
    public Father(){
   
        this.print();
        x=20;
    }

    public void print(){
   
        System.out.println("Father.x="+x);
    }
}

class Son extends Father{
   
    int x=30;
    public Son(){
   
        this.print();
        x=40;
    }
    public void print(){
   
        System.out.println("Son.x="+x);
    }
}

/**
 * @author leowei
 * @date 2021/1/19  - 7:12
 */
public class SonTest {
   
    public static void main(String[] args) {
   
        //m1();
        m2();
        //m3();
    }

    /**
     * 类的非静态成员变量赋值过程
     *  前置1  aload_0   a
     *  前置2  父类初始化
     *  step 1  成员变量  默认初始化   x=0
     *  step 2  成员变量  显示初始化/代码块中初始化  x=10  后打印
     *  step 3  构造器初始化           x=20
     *  step 4  (有了对象后)  对象.属性  赋值
     * 打印内容
     Father.x=10
     20
     */
    private static void m1() {
   
        Father father = new Father();
        System.out.println(father.x);
    }

    /**
     * new Son  先 new  Father
     Son.x=0
     Son.x=30
     40         --- 属性不存在多态,所以一定是 20
     */
    private static void m2(){
   
        Son son=new Son();
        System.out.println(son.x);
    }

    /**
     *

     0 aload_0 ---------------------------------------------------- 加载当前 Son  的 this
     1 invokespecial #1 <com/tiza/jvm/chapter21/Father.<init>>  --- 构造器初始化时候,先init 其父类的(Father) 构造器
                                                                --- Father 构造器会执行new Father() 构造器函数中的 this.print()
                                                                --- 此时 Father 类中的  this.print() 中的 this 是 Son  ,所以会打印 Son.x =0 ;
     4 aload_0
     5 bipush 30                                               ---- 注意,此时才赋值30 给X
     7 putfield #2 <com/tiza/jvm/chapter21/Son.x>
     10 aload_0
     11 invokevirtual #3 <com/tiza/jvm/chapter21/Son.print>
     14 aload_0
     15 bipush 40
     17 putfield #2 <com/tiza/jvm/chapter21/Son.x>
     20 return



     Son.x=0
     Son.x=30
     20              --- 属性不存在多态,所以一定是 20
     */
    private static void m3(){
   
        Father f=new Son();
        System.out.println(f.x);
    }

}

P210-解读Class文件的三种方式 15:47

字节码是一种二进制的类文件,它的内容是JVM指令,不像C,C++由编译器直接生成机器码
什么是字节码 byte code ?
操作码+ 操作数 = 字节码
opcode + operand = byte code

解读字节码的方式三种:

notepad++ (HEX-Editor 插件)
jclasslib 或者 bytecode viewer
javap 反编译指令

https://github.com/chcg/NPP_HexEdit/releases 下载地址
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

P211-Class文件本质和内部数据类型 15:58

P212-Class文件内部结构概述 08:00

在这里插入图片描述

常量类型结构
在这里插入图片描述第一项,字符串 CONSTANT_utf8_info 比较特别
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

P213-字节码数据保存到excel中的操作 07:28

P214-Class文件的标识:魔数 06:33

P215-Class文件版本号 09:40

P216-常量池概述 05:50

P217-常量池计数器 03:53

P218-常量池表中的字面量和符号引用 15:49

在这里插入图片描述

P219-解析得到常量池中所有的常量 16:34

P220-常量池表数据的解读1 10:31

P221-常量池表数据的解读2 10:53

P222-常量池表项数据的总结 08:13

20210119

P223-访问标识 08:20

访问标识 access_flag ;使用两个字节标识,
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

P224-类索引、父类索引、接口索引集合 07:41

当前类索引
父类索引
接口计数器

在这里插入图片描述在这里插入图片描述在这里插入图片描述

P225-字段表集合的整体理解 08:13

字段计数器,字段数组。

字段是指 类级变量 实例变量 ,不包括方法内部,代码内部的变量
字段表,只包含当前类定义的field,不包括父类中的field
在这里插入图片描述

P226-字段表数据的解读 12:01

fields_info1 (字段访问标识+字段名索引+字段描述符索引+属性计数器+属性)
fields_info2
fields_info3
在这里插入图片描述字段表访问标识
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

P227-方法表集合的整体理解 06:51

方法计数器
方法表

在这里插入图片描述在这里插入图片描述

P228-方法表数据的解读 10:48

访问标识
方法名索引
描述符索引
属性计数器
属性集合

在这里插入图片描述在这里插入图片描述方法访问标志
在这里插入图片描述

P229-属性表集合的整理理解 04:47

属性计数器
属性数组

在这里插入图片描述在这里插入图片描述

P230-方法中Code属性的解读 13:44

JAVA8里面定义了23种属性

属性名索引
属性长度
属性表

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

P231-LineNumberTable和LocalVariableTable属性的解读 21:34

在这里插入图片描述在这里插入图片描述

P232-SourceFile属性的解读 07:45

在这里插入图片描述在这里插入图片描述

P233-Class文件结构的小结 03:42

在这里插入图片描述20210120

P234-javac -g操作的说明 13:21

解析Class文件

解析字节码的作用
javac -g 操作
javap 的用法
使用举例
总结

javac xx.java -------- 无局部变量表
javac -g xx.java ------有局部变量表
IDEA EClipse 编译的class 文件使用的是 javac -g ***指令
在这里插入图片描述javac -g localVariableTable
在这里插入图片描述在这里插入图片描述

P235-javap主要参数的使用 21:16

javap

javap
javap -help
javap -version
javap -public javacls.class ----显示公共成员变量和方法
javap -protected javacls.class — ***
javap -private javacls.class ----
javap -package javacls.class — 非私有的
javap -sysinfo javacls.class ---- 类的系统信息
javap -constants javacls.class — 静态常量
javap -s javacls.class ---- 内部类型签名
javap -s -p javacls.class — 内部类型签名(私有及以上)
javap -l javacls.class ---- 输出行号和本地变量表
javap -c javacls.class ---- 对代码进行反汇编
javap -v javacls.class ----- 输出附加信息(包括行号,本地变量表,反汇编,也就是 -v= -l + -c )
javap -v -p javaclass.class -----最全的信息 。

在这里插入图片描述在这里插入图片描述在这里插入图片描述

P236-javap解析得到的文件结构的解读 21:19

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

P237-javap使用小结 05:05

不显示类索引,父类索引,接口结合索引,() , () 等结构
在这里插入图片描述

在这里插入图片描述

字节码指令集与解析举例

字节码指令集与解析举例

01 概述
02 加载与存储指令
03 算数指令
04 类型转换指令
05 对象的创建于访问指令
06 方法调用与返回指令
07 操作数栈指令
08 比较控制指令

在这里插入图片描述

P238-字节码指令集的概述 14:33

操作码,助记符,不能超过256
地址是:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
在这里插入图片描述在这里插入图片描述在这里插入图片描述

P239-指令与数据类型的关系及指令分类 10:11

指令地址:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
iload , int 加载
fload , float 加载
aload , 引用加载

在这里插入图片描述指令分类
在这里插入图片描述20210121

P240-加载与存储指令概述 08:12

加载: 将数据加载到操作数栈中
存储: 将数据存储到局部变量表
在这里插入图片描述

在这里插入图片描述

指令(助记符):
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

指令的分类

加载与存储指令
算术指令
类型转换指令
对象的创建于访问指令
方法调用与返回指令
操作数栈指令
比较控制指令
异常处理指令
同步控制指令

加载和存储指令
加载指令
存储指令

load push ldc const : 入栈
store : 出栈

局部变量表压栈 : xload_ (x = i/l/f/d/a, n=0/1/2/3)
常量池压栈: bipush/sipush/ldc/ldc_w/iconst_/lconst_/dconst_
出栈装入局部变量表: xstore/xstore_ (x = i/l/f/d/a, n=0/1/2/3)

在这里插入图片描述在这里插入图片描述

P241-再谈操作数栈与局部变量表 07:24

在这里插入图片描述操作数栈:存放计算的操作数以及返回结果。
执行每条指令之前,java虚拟机要求该指令的操作数已被压入操作数栈中,在执行指令时,java虚拟机会将该指令所需操作数弹出,并且将指令的结果重新压入栈中。

在这里插入图片描述局部变量表(Local Variables ):
字节码程序将计算的结果缓存在局部变量之中。
java虚拟机将局部变量当成一个数组,依次存放this指针,
局部变量表中
int , float … = 1 slot
long ,double = 2 slot

在这里插入图片描述在这里插入图片描述

P242-局部变量压栈指令 08:44

从局部变量中取出数据,放到栈中。
xload (x= i/l/f/d/a)
在这里插入图片描述

  //局部变量压栈指令
    public void load(int num,Object obj,long count,boolean flag,short[] arr){
   
        System.out.println(num);
        System.out.println(obj);
        System.out.println(count);
        System.out.println(flag);
        System.out.println(arr);
    }

在这里插入图片描述

P243-常量入栈指令 14:13

const:

iconst_x (x= 1-5)

int i=3; iconst_3 — 小于5的,一个指令
int j=6; iconst 6 ----大于5的, 指令 + 数字 ,错错错
int j=6; bipush 6 ----大于5的, 指令 + 数字 ,指令为bipush ,这个写法是对的

lconst_x ( x=1-2)
fconst_x( x=0-2)
dconst_x( x=0-1)
aconst_null

push:

bipush: 8位整数 (-128~127)
sipush: 16位整数 (-32768 ~32767)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值