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

记JVM学习——尚硅谷宋红康JVM全套教程(详解java虚拟机) 记JVM学习——尚硅谷宋红康JVM全套教程(详解java虚拟机) 看完整套视频之后的感触是,讲的真的很好,很细致。推荐大家去学习。 下面是根据视频整理的笔记 尚硅谷宋红康JVM全套教程详解java虚拟机 JVM上篇:内存与垃圾回收 JVM与java体系结构 类加载器子系统 运行时数据区概述及线程 各部分详解 程序计数器 虚拟机栈 本地方法栈 堆 方法区 相关知识 对象的实例化、内存布局与访问定位 直接内存 String table 垃圾回收 概述 垃圾回收相关算法 垃圾回收相关概念 垃 阅读详情

本系列相关链接

尚硅谷 宋红康 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)

sipush 30000 —ok
sipush 32768 ---- 错误

ldc: 万能的ldc 指令 ,

ldc: ---- 一个8位参数
ldc_w: ---- 两个8位参数
ldc2_w: ---- 压入的是 long 或者 double

在这里插入图片描述在这里插入图片描述常量入栈指令:
同样是 int 值 ,用的指令有 iconst bipush ldc 等

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

P244-出栈装入局部变量表指令 14:25

xstore (x为 i/l/f/d/a )
xstore_n

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

P245-算术指令及举例 20:37

记住 store往局部变量表里面存储,就可以了

整形数据算数指令
浮点类型数据算数指令

NaN 表示无穷大,
所有的算数指令:
加法,减法,乘法,除法,求余,取反,自增,位运算符,比较指令。

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

package com.tiza.jvm.chapter22;

import org.junit.Test;

/**
 * @author leowei
 * @date 2021/1/22  - 22:23
 */
public class ArithmeticTest {
    @Test
    public void method1(){
        int i=10;
        double j =i/0.0;
        System.out.println(j);  // 无穷大  Infinity


        double d1=0.0;
        double d2=d1/0.0;
        System.out.println(d2);  //  NaN  : not a number
    }

    // 下面几个方法  编译后看代码
    public void method2(){
        float i=10;
        float j=-i;
        i=-j;
    }

    public void method3_1(){
        int i=100;
        i=i+10;
    }
    public void method3_2(){
        int i=100;
        i+=10;
    }

    public int method4(){
        int a=80;
        int b=7;
        int c=10;
        return (a+b)*c;

    }

    public  int method5(int i,int j) {
        return ((i + j - 1) & (j - 1));
    }

    public void method6_1(){
        int i=10;
        i++;
    }
    public void method6_2(){
        int i=10;
        ++i;
    }
}

P246-算法指令再举例 06:23

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

一个曾经的案例详细过程

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

P247-彻底搞定++运算符 08:15

P248-比较指令的说明 02:46

比较指令:
比较栈顶两个元素大小,并将比较结果入栈。
比较指令有: dcmpg, dcmpl, fcmpg, fcmpl,lcmp .

在这里插入图片描述

P249-宽化类型转换 17:32

在这里插入图片描述在这里插入图片描述int -> long->float -> double
int 升 i2l, i2f, i2d
long 升 l2f, l2d
float 升 f2d

int 4字节
long 4 字节
float 4字节
在这里插入图片描述在这里插入图片描述

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

P250-窄化类型转换 18:50

强制类型转换

int: i2b,i2s,i2c
long l2i
float f2i,f2l
double d2i, d2l ,d2f
在这里插入图片描述在这里插入图片描述

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

package com.tiza.jvm.chapter22;

import com.sun.xml.internal.fastinfoset.stax.factory.StAXOutputFactory;

/**
 * @author leowei
 * @date 2021/1/22  - 23:19
 */
public class ClassCastTest {

    public void upCast1(){
        int i=10;
        long l=i;
        float f=i;
        double d=i;


        float f2 =1;
        double d2 =l;

        double d3 =f2;

    }

    // 精度损失示例
    public void upCAst2(){
        int i=123123123;
        float  f=i;
        System.out.println(f) ;  //  123123120


        long l=123123123123L;
        //long l=123123123123123123L;   // 这个转换会丢失
        double d=l;
        System.out.println("d = " + d);
    }
    //  针对 byte,short  转换为 long 等 , 把 byte 看做int 类型
    public void upCast3(byte b){
        int i=b;
        long l=b;
        double d=b;
    }

    //  针对 byte,short  转换为 long 等 , 把 byte 看做int 类型
    public void upCast4(short s){
        int i=s;
        long l=s;
        double d=s;
    }



    // 窄化类型转化
    public void downCast1(){
        int i=10;
        byte b =(byte) i;
        short s= (short) i;
        char c = (char) i;
        long l=10;
        int i2= (int) l;
        byte b2= (byte) l;
    }

    public void downCast2(){
        float f=10;
        long l = (long) f;
        int i = (int) f;
        byte b = (byte) f;

        double d=10;
        byte b2 = (byte) d;
    }

    public void downCast3(){
        short s=10;
        byte b= (byte) s;
    }

    //  窄化类型转换的精度损失问题
    public void downCast4(){
        int i=128;
        byte b = (byte) i;
        System.out.println("b = " + b);  //  -128
    }

    //  测试 NaN   无穷大
    public void downCast5(){
        double d1 =Double.NaN;   //  0.0/ 0.0  就是  NaN
        int i= (int) d1;
        System.out.println(d1); // NaN
        System.out.println(i);  // 0

        double d2 = Double.POSITIVE_INFINITY;  //POSITIVE_INFINITY = 1.0 / 0.0;
        // double d5 = Double.NEGATIVE_INFINITY; //   NEGATIVE_INFINITY = -1.0 / 0.0;
        long l = (long) d2;
        System.out.println(l);
        System.out.println(Long.MAX_VALUE);

        int j = (int) d2;
        System.out.println(j);
        System.out.println(Integer.MAX_VALUE);

        float f = (float)d2;
        System.out.println(f);
        System.out.println(Float.MAX_VALUE);

    }

}

P251-创建类和数组实例的指令 16:11

20210122

对象创建与访问指令:
创建指令
字段访问指令
数组操作指令
类型检查指令

创建指令: 可以创建类实例和数组对象。
创建类实例:new 这个助记符(字节码指令)用于创建类的实例
创建数组指令: newarray; anewarray ; multianewarray
---------------newarray:创建基本数组
---------------anewarray:创建引用数组
---------------multianewarray:创建多维数组

dup ---------- duplicate 复制

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

 0 new #6 <java/lang/Object>
 3 dup
 4 invokespecial #1 <java/lang/Object.<init>>
 7 astore_1
 8 new #7 <java/io/File>
11 dup
12 ldc #8 <tiza is die>
14 invokespecial #9 <java/io/File.<init>>
17 astore_2
18 return

P252-字段访问指令 11:21

在这里插入图片描述

字段访问指令
对象创建后,可以通过对象访问指令获取对象实例中的字段等。

  1. 访问类字段/ static 字段 指令: getstatic ,putstatic
  2. 访问类实例字段 指令: getfield , putfield

System.out.print(“hello”);
getstatic / getfield : 压栈
putstatic / putfield : 出栈

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

P253-数组操作指令 12:14

数组操作
xastore,xaload
xastore:操作数栈的值存储到数组元素中,
------------- bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore
xaload :加载到操作数栈
------------- baload,caload,saload,iaload,laload,faload,daload,aaload
bcs \ ilfda

xastore 针对数组操作,以iastore为例,它用于给一个int数组给定的索引复制,赋值前准备三个值,
值、索引、数组引用,iastore会弹出这三个值,并将值赋给数组中指定所索引的位置。

xaload 针对数组元素压栈,比如saload压入short数组,执行指令时要求,
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

P254-类型检查指令 04:18

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

P255-方法调用指令 15:35

在这里插入图片描述在这里插入图片描述调用方法方式

invokevirtual : 动态分派
invokeinterface
invokespecial: 构造器,私有,父类方法
invokestatic : 静态方法
invokedynamic

package com.tiza.jvm.chapter22;

import java.util.Date;

/**
 * @author leowei
 * @date 2021/1/25  - 21:43
 */
public class MethodInvokeReturnTest {

    public static void main(String[] args) {

    }

    //方法调用  invokespecial: 静态分配

    /**
     0 new #2 <java/util/Date>
     3 dup
     4 invokespecial #3 <java/util/Date.<init>>
     7 astore_1
     8 new #4 <java/lang/Thread>
     11 dup
     12 invokespecial #5 <java/lang/Thread.<init>>
     15 astore_2
     16 aload_0
     17 invokespecial #6 <java/lang/Object.toString>
     20 pop
     21 aload_0
     22 invokespecial #7 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodPrivate>
     25 return

     */
    public void invoke1(){
        Date date = new Date();       // 情况1: 类实例构造方法
        Thread t1 = new Thread();
        super.toString();              // 情况2: 父类方法
        methodPrivate();               // 情况3: 私有方法
    }
    private void methodPrivate(){

    }
    public void methodPublic(){

    }

    /**
     0 invokestatic #8 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodStatic>
     3 invokestatic #9 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodStaticPrivate>
     6 return

     方法调用  invokestatic
     */
    public void invoke2(){
        methodStatic();
        methodStaticPrivate();
    }
    public static void methodStatic(){

    }
    private static void methodStaticPrivate(){

    }


    /**   方法调用指令  : invokeinterface
     0 new #4 <java/lang/Thread>
     3 dup
     4 invokespecial #5 <java/lang/Thread.<init>>
     7 astore_1
     8 aload_1
     9 invokeinterface #10 <java/lang/Runnable.run> count 1
     14 aconst_null
     15 astore_2
     16 aload_2
     17 bipush 123
     19 invokestatic #11 <java/lang/Integer.valueOf>
     22 invokeinterface #12 <java/lang/Comparable.compareTo> count 2
     27 pop
     28 return
     */
    public void invoke3(){
        Thread t1 = new Thread();  // invokespecial
        ((Runnable)t1).run();      // invokeinterface

        Comparable<Integer> com =null;  // Integer.valueOf  invokestatic
        com.compareTo(123);             // invokeinterface
    }

    /**   方法调用指令 :   invokeVirtual   动态分派 
     0 getstatic #13 <java/lang/System.out>
     3 ldc #14 <hello>
     5 invokevirtual #15 <java/io/PrintStream.println>
     8 new #4 <java/lang/Thread>
     11 dup
     12 invokespecial #5 <java/lang/Thread.<init>>
     15 astore_1
     16 aload_1
     17 invokevirtual #16 <java/lang/Thread.run>
     20 return

     */
    public void invoke4(){
        System.out.println("hello");   // invokevirtual
        Thread t1 = new Thread();      // invokespecial
        t1.run();                      // invokevirtual
    }

}

package com.tiza.jvm.chapter22;

/**
 * @author leowei
 * @date 2021/1/25  - 22:03
 */
public class InterfaceMethodTest {


    /**
     *
     0 new #2 <com/tiza/jvm/chapter22/Son>
     3 dup
     4 invokespecial #3 <com/tiza/jvm/chapter22/Son.<init>>
     7 astore_1
     8 aload_1
     9 invokeinterface #4 <com/tiza/jvm/chapter22/Father.method2> count 1
     14 invokestatic #5 <com/tiza/jvm/chapter22/Father.method1>
     17 return

     * @param args
     */
    public static void main(String[] args) {
        Father f = new Son();
        f.method2();
        Father.method1();
    }
}

interface Father{
    public static void method1(){

    }
    public default void method2(){

    }
}

class Son implements Father{

}

P256-方法返回指令 07:51

return : void
ireturn : int (boolean,byte,char,short)
lreturn : long
freturn : float
dreturn : double
areturn : reference

在这里插入图片描述

package com.tiza.jvm.chapter22;

import java.util.Date;

/**
 * @author leowei
 * @date 2021/1/25  - 21:43
 */
public class MethodInvokeReturnTest {

    public static void main(String[] args) {

    }

    //方法调用  invokespecial: 静态分配

    /**
     0 new #2 <java/util/Date>
     3 dup
     4 invokespecial #3 <java/util/Date.<init>>
     7 astore_1
     8 new #4 <java/lang/Thread>
     11 dup
     12 invokespecial #5 <java/lang/Thread.<init>>
     15 astore_2
     16 aload_0
     17 invokespecial #6 <java/lang/Object.toString>
     20 pop
     21 aload_0
     22 invokespecial #7 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodPrivate>
     25 return

     */
    public void invoke1(){
        Date date = new Date();       // 情况1: 类实例构造方法
        Thread t1 = new Thread();
        super.toString();              // 情况2: 父类方法
        methodPrivate();               // 情况3: 私有方法
    }
    private void methodPrivate(){

    }
    public void methodPublic(){

    }

    /**
     0 invokestatic #8 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodStatic>
     3 invokestatic #9 <com/tiza/jvm/chapter22/MethodInvokeReturnTest.methodStaticPrivate>
     6 return

     方法调用  invokestatic
     */
    public void invoke2(){
        methodStatic();
        methodStaticPrivate();
    }
    public static void methodStatic(){

    }
    private static void methodStaticPrivate(){

    }


    /**   方法调用指令  : invokeinterface
     0 new #4 <java/lang/Thread>
     3 dup
     4 invokespecial #5 <java/lang/Thread.<init>>
     7 astore_1
     8 aload_1
     9 invokeinterface #10 <java/lang/Runnable.run> count 1
     14 aconst_null
     15 astore_2
     16 aload_2
     17 bipush 123
     19 invokestatic #11 <java/lang/Integer.valueOf>
     22 invokeinterface #12 <java/lang/Comparable.compareTo> count 2
     27 pop
     28 return
     */
    public void invoke3(){
        Thread t1 = new Thread();  // invokespecial
        ((Runnable)t1).run();      // invokeinterface

        Comparable<Integer> com =null;  // Integer.valueOf  invokestatic
        com.compareTo(123);             // invokeinterface
    }

    /**   方法调用指令 :   invokeVirtual   动态分派
     0 getstatic #13 <java/lang/System.out>
     3 ldc #14 <hello>
     5 invokevirtual #15 <java/io/PrintStream.println>
     8 new #4 <java/lang/Thread>
     11 dup
     12 invokespecial #5 <java/lang/Thread.<init>>
     15 astore_1
     16 aload_1
     17 invokevirtual #16 <java/lang/Thread.run>
     20 return

     */
    public void invoke4(){
        System.out.println("hello");   // invokevirtual
        Thread t1 = new Thread();      // invokespecial
        t1.run();                      // invokevirtual
    }


    //  ********************   返回值 测试   ************************

    /**
     0 bipush 40
     2 istore_1
     3 iload_1
     4 ireturn

     * @return
     */
    public int returnInt(){
        int i =40;
        return i;
    }

    /**
     *
     0 dconst_0
     1 dreturn

     * @return
     */
    public double returnDouble(){
        return 0.0;
    }


    /**
     *
     0 ldc #17 <hello,world>
     2 areturn

     * @return
     */
    public String returnString(){
        return "hello,world";
    }

    /**
     0 aconst_null
     1 areturn

     * @return
     */
    public int[] returnArr(){
        return null;
    }

    /**
     0 bipush 10
     2 istore_1
     3 iload_1
     4 i2f
     5 freturn

     */
    public float returnFloat(){
        int i=10;
        return i;
    }

    /**
     0 iconst_0
     1 ireturn

     * @return
     */
    public byte returnByte(){
        return  0;
    }


}

P257-操作数栈管理指令 19:20

将元素从栈顶弹出,直接废弃: pop , pop2
复制栈顶(1,2)元素: dup , dup 2
复制栈顶(1,2)元素,将复制结果重新压入栈顶: dup_x1, dup_x2, dup2_x1, dup2_x2;
将栈顶两个Slot数值位置互换: swap
占位指令, Nop 啥都不做

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
package com.tiza.jvm.chapter22;

/**

  • @author leowei

  • @date 2021/1/25 - 23:06
    */
    public class StackOperateTest {
    public static void main(String[] args) {

    }

    private long index;

    /**
    0 new #2 <java/lang/Object>
    3 dup
    4 invokespecial #1 <java/lang/Object.>
    7 astore_1
    8 aload_1
    9 invokevirtual #3 <java/lang/Object.toString>
    12 astore_2
    13 return
    */
    public void print(){
    Object obj = new Object();
    String info = obj.toString();
    }

    /**
    0 aload_0
    1 invokevirtual #4 <com/tiza/jvm/chapter22/StackOperateTest.bar>
    4 pop2
    5 return

    */
    public void foo(){
    bar();
    }

    /**
    0 lconst_0
    1 lreturn

    • @return
      */
      public long bar(){
      return 0;
      }

    /**
    0 aload_0
    1 dup
    2 getfield #5 <com/tiza/jvm/chapter22/StackOperateTest.index>
    5 dup2_x1
    6 lconst_1
    7 ladd
    8 putfield #5 <com/tiza/jvm/chapter22/StackOperateTest.index>
    11 lreturn

    • @return
      */
      public long nextIndex(){
      return index++;
      }
      }

P258-比较指令 08:29

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

P259-条件跳转指令 23:00

1)比较指令 : dcmpg, dcmpl, fcmpg, fcmpl ,lcmp (cmp == compare )
2)条件跳转指令 : ifeq,ifne, iflt,ifle, ifgt ,ifge ,ifnll ,ifnotnull
3)比较条件跳转指令
4)多条件分支跳转指令
5)无条件跳转指令
在这里插入图片描述

package com.tiza.jvm.chapter22;

/**
 * @author leowei
 * @date 2021/1/25  - 23:57
 */
public class IfSwitchForGotoTest {

    public static void main(String[] args) {

    }

    /** 条件跳转指令

     0 iconst_0
     1 istore_1
     2 iload_1
     3 ifne 12 (+9)
     6 bipush 10
     8 istore_1
     9 goto 15 (+6)
     12 bipush 20
     14 istore_1
     15 return
    */
    public void comapre1(){
        int a=0;
        if (a == 0) {
            a=10;
        }else{
            a=20;
        }
    }

    /**
     0 aload_1
     1 ifnonnull 6 (+5)
     4 iconst_1
     5 ireturn
     6 iconst_0
     7 ireturn

     * @param str
     * @return
     */
    public boolean compareNull(String str){
        if(str==null){
            return true;
        }else{
            return false;
        }
    }

    /**
     0 ldc #2 <9.0>
     2 fstore_1
     3 ldc #3 <10.0>
     5 fstore_2
     6 getstatic #4 <java/lang/System.out>
     9 fload_1
     10 fload_2
     11 fcmpg
     12 ifge 19 (+7)
     15 iconst_1
     16 goto 20 (+4)
     19 iconst_0
     20 invokevirtual #5 <java/io/PrintStream.println>
     23 return

     */
    public void compare2() {
        float f1 = 9;
        float f2=10;
        System.out.println(f1<f2);
    }

    public void compare3(){
        int i1=20;
        int i2=20;
        System.out.println(i1<i2);
    }

    /**
     *
     0 dload_1
     1 ldc2_w #6 <50.0>
     4 dcmpl
     5 ifle 10 (+5)
     8 iconst_1
     9 ireturn
     10 iconst_m1
     11 ireturn

     * @param d
     * @return
     */
    
    public int compare4(double d){
        if(d>50.0)
            return  1;
        else
            return -1;
    }

}

P260-比较条件跳转指令 08:16

1)比较指令 : dcmpg, dcmpl, fcmpg, fcmpl ,lcmp (cmp == compare )
2)条件跳转指令 : ifeq,ifne, iflt,ifle, ifgt ,ifge ,ifnll ,ifnotnull
3)比较条件跳转指令 : if_icmpeq, if_icmpne, if_icmplt, if_icmple, if_icmpgt ,if_icmgge, if_acmpeq, if_acmpne
4)多条件分支跳转指令 :
5)无条件跳转指令

在这里插入图片描述

 //  比较条件跳转指令

    /**
     0 bipush 10
     2 istore_1
     3 bipush 20
     5 istore_2
     6 getstatic #4 <java/lang/System.out>
     9 iload_1
     10 iload_2
     11 if_icmple 18 (+7)
     14 iconst_1
     15 goto 19 (+4)
     18 iconst_0
     19 invokevirtual #5 <java/io/PrintStream.println>
     22 return

     */
    public  void ifCompare1(){
        int i=10;
        int j=20;
        System.out.println(i>j);
    }

    public void ifCompare2(){
        short s1=9;
        byte b1=10;
        System.out.println(s1>b1);
    }

    public void ifCompare3(){
        Object obj1 = new Object();
        Object obj2 = new Object();
        System.out.println(obj1==obj2);
        System.out.println(obj1!=obj2);
    }

P261-多条件分支跳转指令 14:11

tableswitch
lookupswitch
在这里插入图片描述

在这里插入图片描述

//  switch test   多条件分支跳转

    /**
     0 iload_1
     1 tableswitch 1 to 3	1:  28 (+27)
     2:  34 (+33)
     3:  40 (+39)
     default:  46 (+45)
     28 bipush 10
     30 istore_2
     31 goto 49 (+18)
     34 bipush 20
     36 istore_2
     37 goto 49 (+12)
     40 bipush 30
     42 istore_2
     43 goto 49 (+6)
     46 bipush 40
     48 istore_2
     49 return

     * @param select
     */

    public void switch1(int select){
        int num;
        switch (select) {
            case 1:
                num = 10;
                break;
            case 2:
                num = 20;
                break;
            case 3:
                num = 30;
                break;
            default:
                num = 40;
        }
    }


    /**
     0 iload_1
     1 lookupswitch 3
     100:  36 (+35)
     200:  48 (+47)
     500:  42 (+41)
     default:  54 (+53)
     36 bipush 10
     ... ...
     * @param select
     */
    public void switch2(int select){
        int num;
        switch (select) {
            case 100:
                num = 10;
                break;
            case 500:
                num = 20;
                break;
            case 200:
                num = 30;
                break;
            default:
                num = 40;
        }
    }

    //JDK 7 新特性: 引入String 类型

    /**
     0 aload_1
     1 astore_2
     2 iconst_m1
     3 istore_3
     4 aload_2
     5 invokevirtual #9 <java/lang/String.hashCode>
     8 lookupswitch 4
     -1842350579:  52 (+44)
     -1837878353:  66 (+58)
     -1734407483:  94 (+86)
     1941980694:  80 (+72)
     default:  105 (+97)
     52 aload_2
     ...
     * @param season
     */
    public void switch3(String season){
        switch(season){
            case "SPRING": break;
            case "SUMMER": break;
            case "AUTUMN": break;
            case "WINTER": break;
        }
    }

P262-无条件跳转指令 15:33

无条件跳转 99% 使用的是goto 指令
在这里插入图片描述
在这里插入图片描述

 // 4 无条件跳转指令

    /**
     0 dconst_0
     1 dstore_1
     2 dload_1
     3 ldc2_w #16 <100.1>
     6 dcmpg
     7 ifge 20 (+13)
     10 ldc #15 <atguigu.com>
     12 astore_3
     13 dload_1
     14 dconst_1
     15 dadd
     16 dstore_1
     17 goto 2 (-15)  ------------goto 指令 
     20 return

     */
    public void whileInt(){
        int i=0;
        while(i<100){
            String s="atguigu.com";
            i++;
        }
    }

    public void whileDouble(){
        double d=0.0;
        while(d<100.1){
            String s="atguigu.com";
            d++;
        }
    }

    public void printFor(){
        short i;
        for (i = 0; i < 100; i++) {
            String s="atguigu.com";
        }
    }


    public void whileTest(){
        int i=1;
        while(i<=100){
            i++;
        }
    }

    public void forTest(){
        for (int i = 0; i < 100; i++) {

        }
    }

    public void doWhileTest(){
        int i=1;
        do{
            i++;
        }while (i<=100);
    }

P263-抛出异常指令 14:07

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

P264-异常处理与异常表 24:25

在这里插入图片描述
在这里插入图片描述https://www.bilibili.com/video/BV1PJ411n7xZ?p=264

P265-同步控制指令 24:14

monitor

https://www.bilibili.com/video/BV1PJ411n7xZ?p=265
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

monitorenter
monitorexit

第三章 类的加载过程详解

P266-类的生命周期概述 15:57

类的加载过程

Loading------------
Linking-------------Verification;Preparation;Resolution
Initialization-------
Using---------------
Unloading---------

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

在这里插入图片描述

P267-加载完成的操作及二进制的获取方式 07:24

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

在这里插入图片描述

package com.tiza.jvm.chapter23;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author leowei
 * @date 2021/1/27  - 22:56
 */
public class LoadingTest {
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName("java.lang.String");
            //获取当前运行时类声明的所有方法
            Method[] ms = clazz.getDeclaredMethods();
            for (Method m : ms) {
                //获取方法的修饰符
                String mod = Modifier.toString(m.getModifiers());
                System.out.print("mod = " + mod);
                //获取方法的返回值类型
                String returnType = m.getReturnType().getSimpleName();
                System.out.print("returnType = " + returnType);
                //获取方法名
                System.out.print(m.getName()+ "(");
                //获取方法的参数列表
                Class<?>[] ps = m.getParameterTypes();
                if(ps.length==0){
                    System.out.print(")");
                }
                for (int i = 0; i < ps.length; i++) {
                    char end = (i==ps.length-1)? ')':',';
                    System.out.print(ps[i].getSimpleName() + end);
                }
                System.out.println();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

P268-类模型与Class实例的位置 08:19

P269-链接之验证环节 13:41

验证

格式验证
语义验证
字节码验证
符号引用验证
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

P270-链接之准备环节 11:15

准备阶段: 为类的静态变量分配内存,并将其初始化为默认值。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

P271-链接之解析环节 11:58

解析阶段(Resolution): 将类、接口、字段、方法的符号引用,转换为直接引用 。
在这里插入图片描述在这里插入图片描述

package com.tiza.jvm.chapter23;

/**
 * @author leowei
 * @date 2021/1/27  - 23:40
 * static final 静态常量值 ,在类加载阶段(Loading,linking,Initializaing,Using,Unloading)的
 * Linking阶段 (验证、准备、解析)的准备阶段就给此类赋值了。
 *
 * 基本数据类型:  非final 变量,准备环节进行默认初始化赋值
 *                 final 变量, 准备环节进行显示赋值
 */
public class LinkingTest {
    private static long id;
    private static final int num=1;
    private static final String conStr ="CONST";
    //同样是给 static final String 赋值,静态字面量有 constantValue ,New 的没有
    private static final String conStr02 = new String("Const02");

}

P272-初始化过程与类初始化方法 08:46

initialization 阶段的操作是: 静态字段,显式赋值。
在这里插入图片描述
在这里插入图片描述

P273-初始化阶段赋值与准备阶段赋值的对比 26:33

链接阶段 准备环节赋值在哪里进行?
结论:
使用 static + final 修饰, and 显式赋值不涉及到方法或构造器的调用 (字面量方式赋值) and 基本数据类型或者String 类型 的显式赋值,在链接阶段的准备环节进行。

在这里插入图片描述

package com.tiza.jvm.chapter23;

import org.omg.CORBA.PUBLIC_MEMBER;

/**
 * @author leowei
 * @date 2021/1/28  - 22:19
 *
 * 链接阶段 准备环节赋值在哪里进行?
 * 结论:
 * 使用  static + final 修饰, and
 *                显式赋值不涉及到方法或构造器的调用 (字面量方式赋值) and
 *                           基本数据类型或者String 类型 的显式赋值,在链接阶段的准备环节进行。
 */
public class InitializationTest2 {

    public static int a=1;                             // 在初始化阶段 <clinit>()中赋值
    public static final int INT_CONSTANT =10;          // 在链接阶段准备环节赋值

    public static final Integer INTEGER_CONSTANT1 = Integer.valueOf(10);  // 在初始化阶段 <clinit>()中赋值
    public static Integer INTEGER_CONSTANT2 = Integer.valueOf(10);        // 在初始化阶段 <clinit>()中赋值

    public static final String s0= "helloworld0";                              // 在链接阶段准备环节赋值
    public static final String s1 = new String("helloworld2");    // 在初始化阶段 <clinit>()中赋值

}

P274-类初始化方法clinit()的线程安全性 07:02

在这里插入图片描述

在这里插入图片描述

package com.tiza.jvm.chapter23;

/**
 * @author leowei
 * @date 2021/1/28  - 22:45
 */
public class StaticDeadLOckMain extends Thread {
    private char flag;

    public StaticDeadLOckMain(char flag){
        this.flag=flag;
        this.setName("Thread "+ flag);
    }

    public void run(){
        System.out.println("-------------- start running flag is "+ flag);
        try {
            Class.forName("com.tiza.jvm.chapter23.Static"+flag);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(getName());
        System.out.println("-------------- finish running flag is "+ flag);
    }

    // A 调用 B  , B  调用  A 进入死循环  
    public static void main(String[] args) {
        StaticDeadLOckMain loadA = new StaticDeadLOckMain('A');
        loadA.start();

        StaticDeadLOckMain loadB = new StaticDeadLOckMain('B');
        loadB.start();
    }

}

// A 加载 B
class StaticA{
    static{
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            Class.forName("com.tiza.jvm.chapter23.StaticB");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("StaticA init OK");
    }
}
// B 加载  A
class StaticB{
    static{
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            Class.forName("com.tiza.jvm.chapter23.StaticA");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("StaticA init OK");
    }
}

运行效果
-------------- start running flag is A
-------------- start running flag is B

P275-何为类的主动使用和被动使用 04:03

P276-类的主动使用1 08:00

dit Configuration : Templates : JUnit
-XX:+TraceClassLoading

  1. 创建一个类的实例时
    1.1 new ***
    1.2 反射,克隆,反序列化

  2. 当调用类的静态方法时 ,即当使用了字节码invokestatic指令。

  3. 当使用类、接口的静态字段时(final修饰特殊考虑)。

  4. 当使用java.lang.reflect包中的方法反射类的方法时。 比如Class.forName(“com.tiza.java.Test”)

  5. 当初始化子类时,如果发现其父类没有初始化,需要先触发其父类的初始化
    (
    java虚拟机初始化一个类的时候,要求他的所有父类都已经被初始化,这条规则不适用于接口
    5.1 初始化一个类时,并不会先初始化它所实现的接口
    5.2 初始化一个接口时,并不会先初始化他的父接口
    5.3 一个父接口不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态字段时,
    才导致该接口被初始化
    )

  6. 如果一个接口定义了default方法,那么直接或者间接实现接口的类的初始化时候,改接口在其之前被初始化

  7. 虚拟机启动时候,执行一个包含main方法的类。
    8.初次调用MethodHandle实例时,初始化改MethodHandle指向的方法所在的类。

P277-类的主动使用2 13:54

package com.tiza.jvm.chapter23;

import org.junit.Test;
import java.util.Random;

/**

  • @author leowei
  • @date 2021/1/28 - 23:55
  • https://www.bilibili.com/video/BV1PJ411n7xZ?p=277
  1. 当使用类、接口的静态字段时(final修饰特殊考虑)

*/
public class ActiveUser2 {

/**
 User 类的初始化过程
 1
 */
@Test
public void test1(){
    System.out.println(User.num);
}

/**
 2
 */
@Test
public void test2(){
    System.out.println(User.num2);
}

/**
 User 类的初始化过程
 8
 */
@Test
public void test3(){
    System.out.println(User.num3);
}

/**
 1
 没有初始化
 */
@Test
public void test4(){
    System.out.println(CompareA.NUM);
}

/**
 CompareA的初始化
 6
 */
@Test
public void test5(){
    System.out.println(CompareA.NUM2);
}

}

class User{
static {
System.out.println(" User 类的初始化过程");
}
public static int num =1;
public static final int num2=2;
public static final int num3 = new Random().nextInt(10);

}

interface CompareA{
public static final Thread t=new Thread(){
{
System.out.println(“CompareA的初始化”);
}
};
public static final int NUM =1 ;
public static final int NUM2 = new Random().nextInt(10);
}

P278-类的主动使用3 11:43

P279-类的主动使用4 07:46

package com.tiza.jvm.chapter23;

import org.junit.Test;

import java.io.Serializable;
import java.util.Random;

/**
 * @author leowei
 * @date 2021/1/29  - 22:28
 */
public class ActiveUser3 {


    /*
    4. 当使用java.lang.reflect包中的方法反射类的方法时。 比如Class.forName("com.tiza.java.Test")
    Order 类的初始化过程
     */
    @Test
    public void test1(){
        try {
            Class  clazz = Class.forName("com.tiza.jvm.chapter23.Order3");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /*
    5. 当初始化子类时,如果发现其父类没有初始化,需要先触发其父类的初始化

    Father 类的初始化
    Son 类的初始化
    1
     */
    @Test
    public void test2(){
        System.out.println(Son.num);
    }

    /*
    5.1  初始化一个类时,并不会先初始化它所实现的接口
    Father 类的初始化
    Son 类的初始化
    1
     */
    @Test
    public void test3(){
        System.out.println(Son2.num);
    }

    /*
    5.2  初始化一个接口时,并不会先初始化他的父接口
    CompareC 的初始化
    0
     */
    @Test
    public void test4(){
        System.out.println(CompareC.NUM1);
    }

}

class Order3 implements Serializable {
    static {
        System.out.println("Order 类的初始化过程");
    }

    public static void method1(){
        System.out.println("order method() .... ");
    }
}


class Father{
    static {
        System.out.println("Father 类的初始化");
    }
}

class Son extends Father{
    static {
        System.out.println("Son 类的初始化");
    }
    public static int num=1;
}

class Son2 extends Father implements CompareB{
    static {
        System.out.println("Son 类的初始化");
    }
    public static int num=1;
}

interface CompareB{
    public static final Thread t =new Thread(){
        {
            System.out.println("CompareB 的初始化");
        }
    };
}

interface CompareC extends CompareB{
    public static final Thread t =new Thread(){
        {
            System.out.println("CompareC 的初始化");
        }
    };

    public static int NUM1 =new Random().nextInt(10);
}


P280-类的被动使用 14:11

类的被动使用, 即是不会进行类的初始化操作,即是不会调用()

  1. 当访问一个静态字段时,只有真正声明该字段的类才会被初始化,
    当通过子类引用父类的静态变量,不会导致子类的初始化
  2. 通过数组定义类的引用,不会触发此类的初始化
  3. 引用常量不会触发此类或接口的初始化,因为常量在链接阶段就已经被显示赋值了
  4. 调用ClassLoader类的LoadClass()方法加载一个类,并不是对类的主动使用,不会导致类的初始化
    Class.forName(**) 阈值相反,是主动调用
package com.tiza.jvm.chapter23;

import org.junit.Test;

/**
 * @author leowei
 * @date 2021/1/29  - 23:25
 *
 *

1. 当访问一个静态字段时,只有真正声明该字段的类才会被初始化,
当通过子类引用父类的静态变量,不会导致子类的初始化
2. 通过数组定义类的引用,不会触发此类的初始化


 *
 *
 */
public class PassiveUse {

    /*
    1. 当访问一个静态字段时,只有真正声明该字段的类才会被初始化,
当通过子类引用父类的静态变量,不会导致子类的初始化

     father is init....
      1
     */
    @Test
    public void test1(){
        System.out.println(ChildA.NUM1);
    }

    //2. 通过数组定义类的引用,不会触发此类的初始化
    //什么都没有打印
    @Test
    public void test2(){
        FatherA[] fathers = new FatherA[10];
    }

}

class FatherA {
    static{
        System.out.println(" father is init....");
    }

    public static int NUM1 = 1;
}

class ChildA extends FatherA{
    static {
        System.out.println(" child is init ...");
    }
}
package com.tiza.jvm.chapter23;

import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.Random;

/**
 * @author leowei
 * @date 2021/1/29  - 23:31
 */
public class PassiveUse2 {

    /*
    1
     */
    @Test
    public void test1(){
        System.out.println(Person.NUM);
    }

    /*
     Person 的初始化
3

     */
    @Test
    public void test2(){
        System.out.println(Person.NUM2);
    }

    /*
     1
     */
    @Test
    public void test3(){
        System.out.println(SerialA.NUM1);
    }

    /*
    SerialA 的初始化
    9
     */
    @Test
    public void test4(){
        System.out.println(SerialA.NUM2);
    }
/*
4. 调用ClassLoader类的LoadClass()方法加载一个类,并不是对类的主动使用,不会导致类的初始化
     Class.forName(**) 阈值相反,是主动调用
 */

    @Test
    public void test5(){
        try {
            ClassLoader.getSystemClassLoader().loadClass("com.tiza.jvm.chapter23.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

class Person{
    static {
        System.out.println(" Person 的初始化 ");
    }
    public static final int NUM =1 ;      //  在链接过程的准备环节就被赋值为1 了 ,
    public static final int NUM2 = new Random().nextInt(10);
}



interface SerialA{
    public static final Thread t =new Thread(){
        {
            System.out.println("SerialA 的初始化");
        }
    };

    public static int NUM1 =1;
    public static int NUM2= new Random().nextInt(10);  // 此赋值操作需要在<clinit>方法中执行
}


P281-类的使用介绍 04:59

P282-类的卸载相关问题 15:47

启动类加载器
扩展类加载器
应用加载器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

4 再谈类的加载器

P283-类加载器的概述 12:35

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

P284-命名空间与类的唯一性 15:57

比较类是否相同,首先要看类的加载器是否一致。
在这里插入图片描述

在这里插入图片描述

package com.tiza.jvm.chapter24;

/**
 * @author leowei
 * @date 2021/1/30  - 7:39
 */
public class ClassLoaderTest {
    public static void main(String[] args) {


        Class<?> clazz = null;
        try {
            clazz = ClassLoader.getSystemClassLoader().loadClass("com.tiza.jvm.chapter24.User");
             System.out.println(clazz.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

P285-类的加载器的分类 07:32

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

P286-引导类加载器的说明 09:02

-XX:+TraceClassLoading
在这里插入图片描述

在这里插入图片描述

P287-扩展类加载器的说明 06:17

在这里插入图片描述

在这里插入图片描述

P288-系统类加载器的说明 04:53

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

P289-用户自定义类加载器的说明 02:09

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

P290-测试不同类使用的类加载器 09:10

在这里插入图片描述

package com.tiza.jvm.chapter24;

/**
 * @author leowei
 * @date 2021/1/30  - 10:26
 */
public class ClassLoaderTest2 {
    /*
classLoader = null
classLoader1 = sun.misc.Launcher$AppClassLoader@14dad5dc
====================
arrStr classLoader is  null
arr3.getClass().getClassLoader() = null
arr2.getClass().getClassLoader() = sun.misc.Launcher$AppClassLoader@14dad5dc
    
     */
    public static void main(String[] args) {
        try {
            // java 类 使用  bootstrap类加载器,打印 null
            ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
            System.out.println("classLoader = " + classLoader);

            //自定义类 使用 系统类加载器  AppClassLoader
            ClassLoader classLoader1 = Class.forName("com.tiza.jvm.chapter24.User").getClassLoader();
            System.out.println("classLoader1 = " + classLoader1);

            System.out.println("====================");
            //数组类型, 使用的加载器与数组元素加载器相同 ,
            // 数组1
            String[] arrStr = new String[10];
            System.out.println("arrStr classLoader is  " + arrStr.getClass().getClassLoader());
            // 数组2
            int[] arr3 = new int[10];
            System.out.println("arr3.getClass().getClassLoader() = " + arr3.getClass().getClassLoader());
            // 数组3
            ClassLoaderTest2[] arr2 = new ClassLoaderTest2[10];
            System.out.println("arr2.getClass().getClassLoader() = " + arr2.getClass().getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

P291-ClassLoader与Launcher的初步剖析 11:50

在这里插入图片描述

P292-ClassLoader的源码解析1 15:04

在这里插入图片描述

P293-ClassLoader的源码解析2 07:08

P294-ClassLoader子类的结构剖析 05:16

在这里插入图片描述

在这里插入图片描述
Class.forName()
classLoader.loadClass()
在这里插入图片描述

P295-双亲委派机制的优势与劣势 22:02

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

P296-三次双亲委派机制的破坏 15:32

在这里插入图片描述

P297-热替换的代码实现 07:16

P298-沙箱安全机制 05:36

P299-自定义类加载器的好处和应用场景 05:43

P300-自定义类加载器的代码实现 15:57

P301-Java9的新特性 15:13

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

JVM从入门到精通(尚硅谷宋红康) 01-JVM内存与垃圾回收篇概述 对 Java 程序员来说,Java 虚拟机(JVM )可以说是既熟悉又神秘,很少有 Java 程序员能够抑制自己探究它的冲动。可惜透彻讲解 JVM 的书籍(尤其是国内出版的)简直少之又少,这里就更不要说能系统讲解 JVM 的视频教程了。尚硅谷的这套 JVM 从入门到精通,绝对可谓是研究 JVM 的程序员及广大 JVM 爱好者的福音。 课程内容分为四个篇章 内存与垃圾回收篇 字节码与类的加载篇 性能监控与调优篇 大厂面试篇 本套视频使用到的软件 # JDK1.8 目前企业 阅读详情

相关推荐

【JVM】尚硅谷宋红康JVM系列1:内存与垃圾回收篇

文章目录 b站视频地址: https://www.bilibili.com/video/BV1PJ411n7xZ/?p=2

Java 2831

尚硅谷JVM全套教程

不从恶人的计谋,不站罪人的道路,不坐亵慢人的座位,惟喜爱耶和华的律法,昼夜思想,这人便为有福!他要像一棵树栽在溪水旁,按时候结果子,叶子也不枯干。凡他所做的尽都顺利。

七叔的博客 1万+

【尚硅谷】JVM-类的加载篇

类模板对象所谓类模板对象,其实就是Java类在JVM内存中的一个快照,JVM将从字节码文件中解析出的常量池、类字段、类方法等信息存储到类模板中,这样JVM在运行期便能通过类模板而获取Java类中的任意信息,能够对Java类的成员变量进行遍历,也能进行Java方法的调用。反射的机制即基于这一基础。如果JVM没有将Java类的声明信息存储起来,则JVM在运行期也无法反射。类模型的位置加载的类在JVM中创建相应的类结构,类结构会存储在方法区(JDK1.8之前:永久代;JDK1.8及之后:元空间)。

時光的博客 1082

最最最常见的Java面试题总结---第三周

String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性   String类中使用字符数组:private final char value[]保存字符串,所以String对象是不可变的。StringBuilder与StringBuffer都继承自Abstra...

陈伟的梦呓 272

尚硅谷2020最新版宋红康JVM教程更新至中篇(java虚拟机详解,jvm从入门到精通)

1

Mason97的博客 1595

第2章:字节码指令集与解析举例.mmap

第2章:字节码指令集与解析举例.mmap

(汇总尚硅谷和精华帖子)JVM总结笔记--详细知识点

一、Java文件编译的过程 1.程序员编写的.java文件; 2.由javac编译成字节码文件.class(为什么编译成class文件,因为JVM只认识class文件) 3.再由JVM编译成电脑认识的文件(对于电脑系统来说文件代表一切) 二、为什么说Java是跨平台文件 这个跨平台是中间语言(JVM)实现的跨平台;Java有JVM从软件层面屏蔽了底层硬件、指令层面的细节让他兼容各种系统。 三、jdk、jre、JVM的区别 Jdk:Java development kit; Java开发工具包; Jre:Ja

qq_41923361的博客 701

第一章:class文件结构.mmap

第一章:class文件结构.mmap

尚硅谷2020最新版宋红康JVM教程-目录

第一篇:内存与垃圾回收篇 最新版宋红康JVM教程-1-JVM简介 尚硅谷2020最新版宋红康JVM教程-2-类加载子系统 尚硅谷2020最新版宋红康JVM教程-3-运行时数据区概述及线程 尚硅谷2020最新版宋红康JVM教程-4-程序计数器 尚硅谷2020最新版宋红康JVM教程-5-虚拟机栈 尚硅谷2020最新版宋红康JVM教程-6-本地方法接口 尚硅谷2020最新版宋红康JVM教程-7-本地方法栈 尚硅谷2020最新版宋红康JVM教程-8-堆 尚硅谷2020

admin741admin的博客 2690

车底盘:阿克曼转向和四轮差速

特性四轮差速四轮转向阿克曼转向转向方式控制左右轮组速度差控制四个轮子的角度控制前轮角度(后轮固定)运动原理滑移摩擦(搓着走)纯滚动(滚着走)近乎纯滚动(低速时)能耗高低(实现纯滚动时)中轮胎磨损非常严重小中灵活性高(可原地旋转)极高(可全向移动)低(转弯半径大)控制精度较低(受地面摩擦影响大)极高高机械复杂度低(通常只需2个驱动电机)极高(需4个转向+4个驱动执行器)中(需1个转向+2个驱动执行器)典型应用坦克、履带车辆、简单AGV、扫地机器人豪华轿车、高性能全向AGV。

bing_feilong的博客 1920

cuda2 but found one of them on device cuda 0

cuda2 but found one of them on device cuda 0 上面问题的重点是,不是cpu和gpu之间的常规问题,而是出现在不同gpu之间的数据。 出问题地方: model = nn.DataParallel(model, device_ids=[2,4]) 先说解决方法: 方案一: model = nn.DataParallel(model, device_ids=[0,2,4]) 前面一定要给一个0的序号,如果0被别人占了呢? 方案二: os.environ["CUDA_

binqiang2wang 662

JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT

JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT 第一章:JVM虚拟机的介绍 1.1虚拟机的分类 虚拟机通常分为两类:系统虚拟机和程序虚机。其中,系统虚拟机是指完全对物理计算机的仿真,而程序虚拟机是指专门为执行单个计算机程序而设计的的。我们的java虚拟机就是典型的程序虚拟机。 1.2Java虚拟机的整体架构 1.3 Java代码的执行流程 1.4 Java的架构模型 java编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构。 具体来说,两种架构的区

qq_22993855的博客 3404

uniapp实现app版本发现新版本后,自动更新

app实现自动更新

oldolder的博客 1283

01-JVM内存与垃圾回收篇概述_尚硅谷JVM学习笔记

对已有占用的空间的数据进行一个回收,那在这部分当中,我们比较重点关注的一个就是如何来判断它是一个垃圾,这就涉及到相关的算法问题。那通常的话,像书里边会包含这个第一个篇章和第二个篇章的内容。那如果你买相关的书的话,一般都会涉及到具体的这里边的某些方面,像内存与垃圾回收,这应该算是比较基本的这个内容了。,就是在八的环境下,我们来跑绝大部分的程序,那后边的话在九、十、十一、十二乃至于十三当中关于一些新的特性,在。像解释器,其实编译器,对吧,包括我们说的垃圾回收,这个垃圾回收器都是在我们的执行引擎这个结构当中的。

weixin_49211183的博客 913

Type-c超声波切割刀

接下来,我将提供Type-C超声波切割刀项目的C代码实现示例,代码将按照上述分层架构和模块化设计进行组织。为了达到3000行以上的代码量,我将尽可能详细地实现各个模块的功能,并添加必要的注释和错误处理。通过采用分层架构和模块化设计,我们可以建立一个可靠、高效、可扩展的系统平台,为产品的成功奠定坚实的基础。实际项目中,需要更详细的硬件驱动、更完善的功能模块、更严格的测试验证和更周全的维护升级计划。针对Type-C超声波切割刀这个项目,我将从以下几个方面详细阐述最适合的代码设计架构,并提供具体的C代码实现。

lianmengde的博客 1189

QT快速配置MSVC2017编译环境(3分钟极简指南)

本文提供了一份3分钟极简指南,帮助开发者快速配置QT的MSVC2017编译环境。通过断网安装、精准勾选组件和配置QT Creator编译器路径等步骤,大幅提升QT开发效率。MSVC2017作为Windows平台高性能C++编译器,特别适合处理大型QT项目,编译速度优势明显。

weixin_30399821的博客 503

尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——01

目录 尚硅谷 宋红康 JVM教程 学习笔记 https://www.bilibili.com/video/BV1PJ411n7xZ P01-JVM内存与垃圾回收篇概述 09:34 P02-如何看待Java上层技术与JVM 20:17 P03-为什么要学习JVM 05:14 P04-面向人群和课程特点 10:15 P05-官方规范下载与参考书目 08:30 P06-跨平台的语言Java和跨语言的平台JVM 15:22 P07-字节码与多语言混合编程 06:25 P08

狗剩的专栏 2498

西门子 S7-1200 G2 高速计数器的使用方法介绍

西门子 S7-1200 G2 高速计数器的使用方法介绍

Robot_PLC_HMI_Automation 1688

【jvm】《尚硅谷宋红康JVM全套教程(详解java虚拟机)》上篇 笔记

是一个很小的内存空间,几乎可用忽略不记。也是运行速度最快的存储区域在jvm规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致任何时间一个线程都只有一个方法执行,也就是所谓的当前方法。程序计数器会存储当前方法正在执行的java方法的jvm指令地址;或者,如果是在执行native方法,则是未指定值(undefined)他是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。............

liangjiayy的博客 4037

YOLOv8改进,YOLOv8添加可变性卷积DCNv2

DCNv2对原始的DCNv1进行了改进,可变形卷积网络的卓越性能源于其适应对象几何变化的能力。通过对其自适应行为的检查,虽然对其神经特征的空间支持比常规的ConvNets更接近于对象结构,但这种支持可能远远超出感兴趣区域,导致特征受到不相关图像内容的影响。为了解决这个问题,我们提出了一种可变形卷积网的重新表述,通过提高建模能力和更强的训练,提高了其专注于相关图像区域的能力。通过更全面地集成网络中的可变形卷积,并引入扩展变形建模范围的调制机制,增强了建模能力。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 3606

2、欧洲期权的赫斯顿模型

本文详细介绍了赫斯顿随机波动率模型在欧洲期权定价中的应用。模型通过引入随机方差过程,克服了布莱克-斯科尔斯模型中波动率恒定的局限性,更贴近市场实际。文章阐述了模型的动态结构、风险中性转换、期权定价公式及其半封闭解的计算方法,并提供了基于VBA的数值实现方案。通过梯形法则与高斯积分等数值方法对比,分析了不同积分策略的精度与效率。同时验证了当波动率为零时,赫斯顿模型退化为布莱克-斯科尔斯模型的一致性。最后讨论了模型的优势、挑战及实际应用建议,强调了数值积分稳定性和参数估计的重要性。

tequila的博客 348

尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——02

08 堆 P66-堆空间的概述_进程中堆的唯一性 15:28 方法区与堆,都是进程共享的,一个进程对应一个 JVM 实例 一个进程中的多个线程共享 堆及方法区, 每个线程,有一组 虚拟机栈、本地方法栈、程序计数器 Java堆区在JVM启动的时候就创建了,其空间大小就确定了。是JVM管理的最大内存空间。堆内存大小是可以调节的。 C:\developer_tools\Java\jdk1.8.0_45\bin P67-堆空间关于对象创建和和GC的概述 17:38 P68-堆的细分内存结构

狗剩的专栏 1813

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

尚硅谷2020最新版宋红康JVM教程学习笔记 一 类加载子系统

JAVA语言是跨平台的语言,JVM虚拟机是跨语言的平台。JVM虚拟机并不关心字节码文件是由什么语言生成的。只有不同的语言通过编译器生成符合JVM虚拟机规范的字节码文件,JVM就能够运行。JAVA就是通过编译生成字节码文件,然后再在JVM上运行。因此JAVA语言可以一次编译到处运行。 虚拟机 虚拟机是一台虚拟计算机,是用来执行虚拟计算机指令的软件。虚拟机可以分为系统虚拟机和程序虚拟机。 如VMware就是系统虚拟机,他是对物理计算机的仿真。 Java虚拟机是程序虚拟机,他专门为执行单个计算机程序而设计,在ja

qq_30033509的博客 1293

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

尚硅谷-宋红康-JVM上中下篇完整笔记

尚硅谷-康师傅-jvm详细笔记,欢迎转载,放心食用。

ctflq的博客 1万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

JVM学习总结:字节码篇

Java JVM 字节码

1196

JVM学习总结:类的加载篇

JVM 类的加载

788
上一篇: SpringBoot配置文件加载位置与优先级
下一篇: 尚硅谷Kafka教程 2019 --- 狗剩学习笔记
wei198621
博客等级 码龄20年 169粉丝 388原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值