4.1 类加载到JVM
基本作用: 加载Class文件
代码示例
package cn.guardwhy.jvm;
public class Student {
public static void main(String[] args) {
// 1.类是模板,对象是具体的
Student student1 = new Student();
Student student2 = new Student();
Student student3 = new Student();
System.out.println(student1.hashCode()); // 460141958
System.out.println(student2.hashCode()); // 1163157884
System.out.println(student3.hashCode()); // 1956725890
// 2.创建类对象
Class c1 = student1.getClass();
Class c2 = student1.getClass();
Class c3 = student1.getClass();
System.out.println(c1.hashCode()); // 685325104
System.out.println(c2.hashCode()); // 685325104
System.out.println(c3.hashCode()); // 685325104
}
}
4.2 ClassLoader分类
两种类型的类加载器
Java虚拟机自带的加载器
- 根类加载器(BootStrap ClassLoader) sun.boot.class.path (加载系统的包,包含jdk核心库里的类)。
- 扩展类加载器(Extension ClassLoader) java.ext.dirs(加载扩展jar包中的类)
- 系统(应用)类加载器((AppClassLoader) java.class.path(加载编写的类,编译后的类)
代码示例
package cn.guardwhy.jvm_01;
public class Student {
public static void main(String[] args) {
// 1.类是模板,对象是具体的
Student student1 = new Student();
// 2.创建类Class对象
Class c1 = student1.getClass();
ClassLoader classLoader = c1.getClassLoader();
System.out.println(classLoader); // AppClassLoader
System.out.println(classLoader.getParent()); // ExtClassLoader /jre/lib/ext
System.out.println(classLoader.getParent().getParent()); // null , 1:不存在, 2:Java程序获取不到
}
}
用户自定义的类加载器
Java.long.ClassLoader的子类(继承),用户可以定制类的加载方式
代码示例
package cn.guardwhy.jvm_01;
/*
* 应用程序加载器
*/
public class Student {
@Override
public String toString() {
return "Hello world!!";
}
public static void main(String[] args) {
// 1.实例化对象
Student student1 = new Student();
// 拓展类加载器
System.out.println(student1.getClass().getClassLoader()); // AppClassLoader
System.out.println(student1.toString()); // Hello world!!
}
}
4.3 双亲委派机制
双亲委派机制的工作原理:一层一层的让父类去加载,最顶层父类不能加载往下数,依次类推。
-
类加载器收到类加载的请求。
-
把这个请求委托给父加载器去完成,一直向上委托,直到启动类加载器;
-
启动器加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。
-
重复步骤三。
代码示例
package java.lang;
/*
* 双亲委派机制:安全。
* APP-->EXC--BOOT(最终执行)
* BOOT
* EXC
*/
public class String {
@Override
public String toString() {
return "Hello world";
}
public static void main(String[] args) {
// 实例化对象
String s1 = new String();
s1.toString();
/*错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
*/
}
}
执行结果
String 默认情况下是启动类加载器进行加载的,自定义一个String 。自定义的String 可以正常编译,但是永远无法被加载运行。自定义String 加载时,总是启动类加载器,而不是自定义加载器,也不会是其他的加载器。双亲委派机制可以确保Java核心类库所提供的类,不会被自定义的类所替代。