目录
1.4 如果自己手写一个Java虚拟机的话,主要考虑哪些结构呢?
1、内存结构概述
1.1 简图
1.2 详细图 (中文)
1.3 详细图(英文)
1.4 如果自己手写一个Java虚拟机的话,主要考虑哪些结构呢?
类加载器 和 执行引擎
2、类加载器与类加载过程
2.1 类加载子系统的作用
2.2 类加载ClassLoader扮演的角色
2.3 类的加载过程
2.3.1 加载阶段
2.3.2 链接阶段
package com.atguigu.java; /** * @author shkstart * @create 2020 下午 6:01 */ public class ClassInitTest { private static int num = 1; static{ num = 2; number = 20; System.out.println(num); //System.out.println(number);//报错:非法的前向引用。 } //linking之prepare: number = 0 --> initial: 20 --> 10 private static int number = 10; public static void main(String[] args) { System.out.println(ClassInitTest.num);//2 System.out.println(ClassInitTest.number);//10 } }
2.3.3 初始化阶段
package com.atguigu.java; /** * @author shkstart * @create 2020 下午 8:34 * @desc <clinit>() 与 类的构造器 */ public class ClinitTest { //任何一个类声明以后,内部至少存在一个类的构造器 private int a = 1; private static int c = 3; public static void main(String[] args) { int b = 2; } public ClinitTest(){ a = 10; int d = 20; } }
package com.atguigu.java; public class ClinitFirst { public static int a = 18; public static int b = 18; static { b = 20; } public static void main(String[] args) { System.out.println("a="+a+";b="+b);//a=18;b=20 } }
类的<clinit>()方法如下
package com.atguigu.java; /** * @author shkstart * @create 2020 下午 8:40 * @desc 若该类具有父类,JVM会保证子类的<clinit>()执行前,父类的<clinit>()先执行完毕 */ public class ClinitTest1 { static class Father{ public static int A = 1; static{ A = 2; } } static class Son extends Father{ public static int B = A; } public static void main(String[] args) { //加载Father类,其次加载Son类。 System.out.println(Son.B);//2 } }
package com.atguigu.java; /** * @author shkstart * @create 2020 上午 11:23 * @desc 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁 */ public class DeadThreadTest { public static void main(String[] args) { Runnable r = () -> { System.out.println(Thread.currentThread().getName() + "开始"); DeadThread dead = new DeadThread(); System.out.println(Thread.currentThread().getName() + "结束"); }; Thread t1 = new Thread(r,"线程1"); Thread t2 = new Thread(r,"线程2"); t1.start(); t2.start(); } } class DeadThread{ static{ if(true){ System.out.println(Thread.currentThread().getName() + "初始化当前类"); while(true){ } } } }
3、类加载器的分类
3.1 类加载器的分类
package com.atguigu.java1; /** * @author shkstart * @create 2020 上午 9:22 */ public class ClassLoaderTest { public static void main(String[] args) { //获取系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 //获取其上层:扩展类加载器 ClassLoader extClassLoader = systemClassLoader.getParent(); System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@1540e19d //获取其上层:获取不到引导类加载器 ClassLoader bootstrapClassLoader = extClassLoader.getParent(); System.out.println(bootstrapClassLoader);//null //对于用户自定义类来说:默认使用系统类加载器进行加载 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 //String类使用引导类加载器进行加载的。---> Java的核心类库都是使用引导类加载器进行加载的。 ClassLoader classLoader1 = String.class.getClassLoader(); System.out.println(classLoader1);//null } }
package com.atguigu.java1; import sun.security.ec.CurveDB; import java.net.URL; import java.security.Provider; /** * @author shkstart * @create 2020 上午 12:02 */ public class ClassLoaderTest1 { public static void main(String[] args) { System.out.println("**********启动类加载器**************"); //获取BootstrapClassLoader能够加载的api的路径 URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs(); for (URL element : urLs) { System.out.println(element.toExternalForm()); } //从上面的路径中随意选择一个类,来看看他的类加载器是什么:引导类加载器 ClassLoader classLoader = Provider.class.getClassLoader(); System.out.println(classLoader); System.out.println("***********扩展类加载器*************"); String extDirs = System.getProperty("java.ext.dirs"); for (String path : extDirs.split(";")) { System.out.println(path); } //从上面的路径中随意选择一个类,来看看他的类加载器是什么:扩展类加载器 ClassLoader classLoader1 = CurveDB.class.getClassLoader(); System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1540e19d } }
3.1.1 启动类加载器
3.1.2 扩展类加载器
3.1.3 应用类加载器
3.1.4 自定义类加载器
3.1.5 自定义加载器的实现步骤
package com.atguigu.java1; import java.io.FileNotFoundException; /** * 自定义用户类加载器 * @author shkstart * @create 2019 下午 12:21 */ public class CustomClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] result = getClassFromCustomPath(name); if(result == null){ throw new FileNotFoundException(); }else{ return defineClass(name,result,0,result.length); } } catch (FileNotFoundException e) { e.printStackTrace(); } throw new ClassNotFoundException(name); } private byte[] getClassFromCustomPath(String name){ //从自定义路径中加载指定类:细节略 //如果指定路径的字节码文件进行了加密,则需要在此方法中进行解密操作。 return null; } public static void main(String[] args) { CustomClassLoader customClassLoader = new CustomClassLoader(); try { Class<?> clazz = Class.forName("One",true,customClassLoader); Object obj = clazz.newInstance(); System.out.println(obj.getClass().getClassLoader()); } catch (Exception e) { e.printStackTrace(); } } }
4、ClassLoader的使用说明
4.1 关于ClassLoder
4.2 获取ClassLoader的途径
package com.atguigu.java1; /** * @author shkstart * @create 2020 上午 10:59 */ public class ClassLoaderTest2 { public static void main(String[] args) { try { //1. ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader(); System.out.println(classLoader); //2. ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader(); System.out.println(classLoader1); //3. ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent(); System.out.println(classLoader2); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
5、双亲委派机制
5.1 定义
5.2 工作原理
5.3 举例
5.4 优势
5.5 沙箱安全机制
6、其他
6.1 判断两个class对象是否为同一个类
6.2 对类加载器的引用
6.3 类的主动使用和被动使用