Native Method 就是本地方法
类字节码
![未命名文件 (3).png](https://img-blog.csdnimg.cn/img_convert/f5a7a5739a374cd0e51286c1a9efa0d1.png#clientId=u49fc9ce4-6e48-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=342&id=u6fe92853&margin=[object Object]&name=未命名文件 (3).png&originHeight=331&originWidth=668&originalType=binary&ratio=1&rotation=0&showTitle=false&size=21935&status=done&style=none&taskId=u96590149-2be6-41b4-9cb6-ef3c261c7a9&title=&width=690)
计算机不能直接运行java代码
Java内存结构
![JVM内存.png](https://img-blog.csdnimg.cn/img_convert/9c7529b91eeb814efb1fa1e628013269.png#clientId=u8611501d-4645-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u0d3d3e03&margin=[object Object]&name=JVM内存.png&originHeight=1823&originWidth=1989&originalType=binary&ratio=1&rotation=0&showTitle=false&size=262489&status=done&style=none&taskId=uf453dc2f-7e5e-4826-9cfc-40f20a1faac&title=)
类加载器
**Bootstrap ClassLoader (引导程序加载器/启动类加载器) **
最顶层的类加载器使用,使用C++写的,是所有加载类的父类
负责%JAVA_HOME%/lib
Extension ClassLoader (扩展类加载器)
Java实现, %JAVA_HOME%/lib/ext,或者所有背java.ext.dirs系统变量所指定的路径下的jar包
AppClassLoader(应用加载器Applaction ClassLoader
用户加载器,负责加载当前应用classpath下所有jar包和类
public class Main{
public static void main(String[] args) {
System.out.println(Main.class.getClassLoader());
System.out.println(Main.class.getClassLoader().getParent());
System.out.println(Main.class.getClassLoader().getParent().getParent());
}
}
//
sun.misc.Launcher$AppClassLoader@18b4aac2 //应用加载器
sun.misc.Launcher$ExtClassLoader@330bedb4 // 扩展类加载器
null //null是BootStrap ClassLoader
Linking
Verify(验证)保证被加载的类的正确性
- 文件格式验证:验证字节流是不是符合Class文件格式的规范
- 元数据验证:对字节码描述的信息进行语义分析,确定描述的信息符合Java语言规范,比如这个类是不是有父类?
- 字节码验证:通过数据流和控制流分析,确定语义是合法的,符合逻辑的
- 符号引用验证:确保解析动作可以正确的执行
Perpare(准备):为类的静态变量分配内存,并将其初始化为默认值
- 此时内存分配的仅为类变量(static),不包括实例变量。对象实例化的时候,会随着变量初始化的时候被分配到堆中
- 此时的初始值,通常是数据类型的默认值(0,0L,false,null),不是java代码中显式被赋予的值
public static int a = 3;
//在Linking过程中被初始化的值是a = 0;
// 把值初始化为3在初始化的时候才会执行
Resolve(解决,解析):把类中的符号引用转换为直接引用。
虚拟机将常量池的符号引用替换为直接引用的过程,解析动作主要正对类、接口、字段、类方法、接口方法、方法类型、方法句柄、调用点
**符号引用:**一组符号来描述目标,可以是任何字面量。
**直接引用:**直接指向目标的指针,相对偏移量或一个间接定位到目标的句柄。???
https://blog.csdn.net/luzhensmart/article/details/82627897
注意:
对于被static和final修饰的常量必须显示赋值
package com.chaossnow;
import com.chaossnow.absclass.Human;
/**
* @program: findwordcode
* @description:
* @author: chaos
* @create: 2022-09-11 15:18
**/
public class InitializedTest{
public int value; //默认0
public static int staticValue;//默认0
public static Human chaos;
public Human chao;
public int[] nums;
public int[] ints = new int[6];
//ConstantValue 在编译的时候就会根据常量的设置,将CONSTANT_VALUE赋值为3,会在编译期将其结果放入调用它的类的常量池中
public static final int CONSTANT_VALUE = 3;
//对于同时被static和final,必须要显示赋值
public static final int SUCCEESS_HEAD = 1;
public static void main(String[] args) {
InitializedTest initializedTest = new InitializedTest();
initializedTest.dome();
}
public static void say(){
System.out.println("我是初始化");
}
public void dome(){
String name;
// System.out.println("我是: "+ name);对于局部变量必须在初始化之间就显示赋值,编译不通过
System.out.println("我是普通全局基本变量:" + value);//0
System.out.println("我是静态全局基本变量: "+ staticValue);//0
//对于引用数据对象,在没有显示指定实例化对象的时候,会赋予默认的零值:null
System.out.println("我是静态全局引用变量:" + chaos); //null
System.out.println("我是普通全局引用变量:" + chao); //null
System.out.println("我是普通全局引用数组变量:" + nums); //null
// System.out.println(nums[0]);//对于没有引用的对象,访问其中的元素或者方法会报NullPointerException
System.out.println("我是普通全局引用数组变量(已初始化):" + ints); //[I@330bedb4 对象
System.out.println("我是普通全局引用数组变量(已初始化)中的元素:" + ints[0]); // 默认值
System.out.println("我是常量:" + CONSTANT_VALUE);
}
}
/*
"C:\Program Files\Java\jdk1.8.0_333\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\lib\idea_rt.jar=59705:C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_333\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\rt.jar;C:\Users\chaos\Desktop\work-master\findwordcode\Steam\target\classes;C:\Users\chaos\Desktop\work-master\findwordcode\newcode\target\classes;C:\Users\chaos\.m2\repository\org\testng\testng\7.6.1\testng-7.6.1.jar;C:\Users\chaos\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\chaos\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;C:\Users\chaos\.m2\repository\com\beust\jcommander\1.82\jcommander-1.82.jar;C:\Users\chaos\.m2\repository\org\webjars\jquery\3.6.0\jquery-3.6.0.jar;C:\Users\chaos\Desktop\work-master\findwordcode\POJO\target\classes" com.chaossnow.InitializedTest
我是普通全局基本变量:0
我是静态全局基本变量: 0
我是静态全局引用变量:null
我是普通全局引用变量:null
我是普通全局引用数组变量:null
我是普通全局引用数组变量(已初始化):[I@330bedb4
我是普通全局引用数组变量(已初始化)中的元素:0
我是常量:3
*/
初始化(Initiatizion
初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对**类变量(静态变量)**进行初始化。
两种方式:
声明类变量时指定初始值
使用静态代码块为其指定初始值
package com.chaossnow.streamtest;
/**
* @program: findwordcode
* @description:
* @author: chaos
* @create: 2022-09-11 16:10
**/
public class InitializedDome {
//静态全局变量
public static int value = 3;
public static String name;
//静态代码块
static {
name = "I am Initialize";
}
//静态代码块
static {
System.out.println("我是静态代码块中的Name:" + name);
System.out.println("我是静态代码块中的value:" + value);
}
//静态代码块
static {
value = 6;
}
public static void main(String[] args) {
System.out.println("我是静态代码块中的main方法中name: " +name);
System.out.println("我是静态代码块中的main方法中value: " + value);
}
}
JVM初始化顺序:
如果this.class 还没有加载(ClassLoader)或连接(Linking),则程序先加载并连接this.class
如果this.class 的直接父类还没有被初始化,则先初始化其父类
如果类中有初始化语句,系统依次执行这些初始化语句。
初始化顺序:
public class Father{
public static String staticField = "父亲-静态变量";
public String field = "父亲-普通变量";
//初始化块
{
System.out.println(field);
System.out.println("父亲-初始化代码块");
}
//静态初始化块
static {
System.out.println(staticField);
System.out.println("父亲-静态代码块");
}
public void work(){
System.out.println("父亲-工作");
}
public Father(){
System.out.println("父亲-构造方法");
}
}
package com.chaossnow.initializzed;
/**
* @program: findwordcode
* @description:
* @author: chaos
* @create: 2022-09-11 16:25
**/
public class Son extends Father{
public static String staticField = "儿子-静态变量";
public String field = "儿子-普通变量";
//初始化块
{
System.out.println(field);
System.out.println("儿子-初始化代码块");
}
//静态初始化块
static {
System.out.println(staticField);
System.out.println("儿子-静态代码块");
}
public void work(){
System.out.println("儿子-工作");
}
public Son(){
System.out.println("儿子-构造方法");
}
public static void main(String[] args) {
System.out.println("main 方法");
new Son();
}
}
/*
父亲-静态变量
父亲-静态初始化代码块
儿子-静态变量
儿子-静态初始化代码块
main 方法
父亲-普通变量
父亲-初始化代码块
父亲-构造方法
儿子-普通变量
儿子-初始化代码块
儿子-构造方法
*/
/*
不考虑继承情况
静态变量、静态代码块
变量,非静态代码块
构造函数
*/
原则:
- 首先执行static初始化,先执行父类的static,在执行子类的static。这是因为子类的成功初始化可能与父类的初始化有关。
- 再初始化普通变量和普通代码块
- 最后执行构造方法。
https://blog.csdn.net/qq_25665807/article/details/74452181
类初始化的时机:只有在对类的主动使用,才会导致类的初始化
- 创建类的实例,new
- 访问类的静态变量或者调用类的静态方法
- 反射
- 初始化子类,父类也会被初始化
- Java虚拟机启动时表明为启动类的类(Java Test)
卸载
- 使用System.exit() 方法
- 正常执行结束
- 执行过程中遇到了错误或者异常导致的异常终止
- 操作系统错误导致java虚拟机终止
JVM类加载机制
**全盘负责:**当一个ClassLoader负责加载某个Class的时候,该Class所依赖或引用的Class也由该ClassLoader负责载入,除非显式声明。
**父类委托:**先让父类加载器进行加载,只有在父类加载器无法加载该类的时候才会启用本类进行加载。
**缓存机制:**缓存机制会保证所有加载过的Class都写入缓存。优先加载ClassLoader缓存区里面的数据。找不到才会重新读取该类的二进制数据。
**双亲委派机制:**如果一个类加载器收到了类加载请求,自己不会首先就去尝试加载这个类。而是把请委托给自己的父加载器去完成,依次向上。所有的类加载请求最终都应该被传递到最顶层的类加载器中,只有父类在他的搜索范围没有找到所需要的类的时候,子ClassLoader才会自己尝试去加载。
双亲委派机制:
- AppClassLoader 加载一个class时,它自己不会直接去加载,把类加载请求委派给父类加载器ExtensionClassLoader来加载。
- ExtensionClassLoader加载一个class,他自己也不会直接去加载,他会把类加载请求委派给父类加载器BootstrapClassLoader去加载。
- 当BootstrapClassLoader加载失败(%JAVA_HOME%/lib中没有找到该class),会使用ExtensionClassLoader来尝试进行加载。
- 如果ExtClassLoader也加载失败,则会使用AppClassLoader来进行加载,如果AppClassLoader也加载失败,则会爆出ClassNofFountException