JVM 类加载机制

JVM 类加载机制

先来一张图,盗的
在这里插入图片描述

加载

加载class对象,从JAR,WAR等路径加载class文件,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口。

类加载的过程使用的是 双亲委派模式模型
在这里插入图片描述简单的解释就是,子类在接收类加载请求的时候,优先使用父类的加载器,父类没有的时候,才会给子类加载,如果有直接放回。 主要解决的问题就是 防止篡改JDK原始类。如果开发者尝试编写一个与rt.jar类库中重名的Java类,可以正常编译,但是永远无法被加载运行。例如不能定义一个 java.lang的包名的类/

其中:Bootstrap 启动类加载器,加载<JAVA_HOME>/lib 里面的jar,
Extension 扩展类加载器。加载<JAVA_HOME>/lib/ext 里面的jar
Application 应用类加载器 加载用户自定义JAR

验证

这一阶段的主要目的是为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。就是校验文件的可用性

准备

正式为类变量,类方法(static)分配内存并设置类变量的初始值,这些内存都在方法区内分配。

解析

解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程
简单的说就是,将原本使用符号代替的常量,直接使用 内存地址

初始化

初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码

这么说类初始化有点不好理解。抄了别人的几个例子解释起来比较容易理解

package com.jvm;

public class B {
	static int i = 1;

		static String staicStr = "staicStr";

	static final String staicFinalStr = "staicFinalStr";


	static {
		System.out.println("B1 static:i=" + i);
	}

	static {
		i++;
		System.out.println("B2 static:i=" + i);
	}

	int j = 1;

	public B() {
		i++;
		j++;
		System.out.println("b: i=" + i + ",j=" + j);
	}

	{
		i++;
		j++;
		System.out.println("b 非静态   i=" + i + ",j=" + j);
	}

		public static void cc() {
		System.out.println("B  静态 static cc");
	}

}

package com.jvm;

public class A extends B {

	static int i = 1;

	static {
		System.out.println("A1 static:i=" + i);
	}

	static {
		i++;
		System.out.println("A2 static:i=" + i);
	}
	
	int j = 1;

	

	public A() {
		// super();
		i++;
		j++;
		System.out.println("a: i=" + i + ",j=" + j);
	}

	{
		i++;
		j++;
		System.out.println("a 非静态   i=" + i + ",j=" + j);
	}

	public void test() {
		i++;
		System.out.println("a test i=" + i);
	}

	public static void test1() {
		i++;
		System.out.println("a  static test i=" + i);
	}
}

1. 第一次执行
package com.jvm;

public class aa {

	public static void main(String[] args) {
		 A a = new A();
		 a.test(); 
	}
}

结果:
B1 static:i=1
B2 static:i=2
A1 static:i=1
A2 static:i=2
b 非静态   i=3,j=2
b: i=4,j=3
a 非静态   i=3,j=2
a: i=4,j=3
a test i=5

父类是B,子类是A,A初始化后执行了那些方法

  1. 按顺序执行B 的静态方法,
  2. 按顺序执行A 的静态方法
  3. 执行B的非静态块代码
  4. 执行B的构造函数
  5. 执行A的非静态块代码
  6. 执行A的构造函数
  7. 最后执行A的方法
    两者变量值是独立的,互不影响
2.第二次执行
package com.jvm;

public class aa {

	public static void main(String[] args) {
		 A.test1();
	}
}

结果:
B1 static:i=1
B2 static:i=2
A1 static:i=1
A2 static:i=2
a static  test i=3

只执行A的静态方法

  1. 按顺序初始化 B的静态方法
  2. 按顺序初始化A的静态方法
  3. 执行A的静态方法

非静态方法都没有执行

3. 第三次执行
package com.jvm;

public class aa {

	public static void main(String[] args) {
		 A.cc();
	}
}

结果:
B1 static:i=1
B2 static:i=2
B  静态 static cc


执行A.cc 方法,但是cc方法是父类B的静态方法

  1. 按顺序执行B的静态方法
  2. 执行B的静态方法CC

没有初始化A的 静态和 非静态还有 构造函数

第四次执行
package com.jvm;

public class aa {

	public static void main(String[] args) {
		System.out.println(A.staicStr);
	}
}

结果:
B1 static:i=1
B2 static:i=2
staicStr

这个结果和第三次结果一致,就不做说明

第5次
package com.jvm;

public class aa {

	public static void main(String[] args) {

		System.out.println(A.staicFinalStr);

	}
}

结果:
staicFinalStr

这次执行的是A的父类,里面的一个 final 常量
发现直接打印了这个常量的值,静态方法和 非静态方法 都没有执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值