双亲委派
双亲委派
前提:类的生命周期:类的加载->连接(验证,准备,解析)->初始化->使用->类的卸载
class MyObject{ static int num1 = 100; static int num2 = 100;//在类的连接状态时 会先给num2 赋值0,然后在赋值阶段给赋值为100 public MyObject() { num1 = 200; num2 = 200; //在创建对象的时候会给赋值为200 } static MyObject object = new MyObject(); public static MyObject getInstance() { return object; } @Override public String toString() { // TODO Auto-generated method stub return "num1:"+this.num1+"\r\n"+"num2:"+num2; } } public class TestLoader { public static void main(String[] args) { MyObject object = MyObject.getInstance(); System.out.println(object.toString()); } }
结果:
num1:200
num2:200
如果把num2的静态赋值的位置进行改变:
class MyObject{ static int num1 = 100; //static int num2 = 100;//在类的连接状态时 会先给num2 赋默认值为0,然后在赋值阶段给赋值为100 public MyObject() { num1 = 200; num2 = 200; //在创建对象的时候会给赋值为200 } static MyObject object = new MyObject(); static int num2 = 100; public static MyObject getInstance() { return object; } @Override public String toString() { // TODO Auto-generated method stub return "num1:"+this.num1+"\r\n"+"num2:"+num2; } } public class TestLoader { public static void main(String[] args) { MyObject object = MyObject.getInstance(); System.out.println(object.toString()); } }
结果:
num1:200
num2:100

双亲委派:双亲是指:1.JVM自带的加载器(在JVM的内部所包含,C++) 2.用户自定义的加载器(独立于JVM之外的加载器,Java)



jdk中的getClassLoader api的解释:
Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.
public class TestParentClassLoader { public static void main(String[] args) throws Exception {
//加载 rt.jar里面的类,用根加载器BootStrap 解析 Class clz = Class.forName("java.lang.String"); ClassLoader loader = clz.getClassLoader(); System.out.println(loader); } }
结果:null
package jvm.classloader; public class TestParentClassLoader { public static void main(String[] args) throws Exception { Class clz1 = Class.forName("jvm.classloader.TestParentClassLoader"); ClassLoader loader1 = clz1.getClassLoader(); System.out.println(loader1); } }
结果:sun.misc.Launcher$AppClassLoader@73d16e93

获取用户自定义的类的加载器有两种方式:
1.Class.forName().getClassLoader();
2.ClassLoader.getSystem
public class GetClassLoaderDemo { public static void main(String[] args) throws Exception { //第一种方式: ClassLoader loader = Class.forName("jvm.classloader.GetClassLoaderDemo").getClassLoader(); System.out.println(loader); //第二种方式: ClassLoader loader2 = ClassLoader.getSystemClassLoader(); System.out.println(loader2); } }
结果:
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$AppClassLoader@73d16e93
获取扩展类加载器和根加载器可以使用getParent()方式:
public class GetClassLoaderDemo { public static void main(String[] args) throws Exception { //第一种方式: ClassLoader loader = Class.forName("jvm.classloader.GetClassLoaderDemo").getClassLoader(); System.out.println(loader); //第二种方式: ClassLoader loader2 = ClassLoader.getSystemClassLoader(); System.out.println(loader2); ClassLoader parentLoader1 = loader2.getParent(); ClassLoader parentLoader2 = parentLoader1.getParent(); System.out.println(parentLoader1);//sun.misc.Launcher$ExtClassLoader@15db9742 System.out.println(parentLoader2); //null } }
自定义类的加载器


The class loader for an array class, as returned by {@link
* Class#getClassLoader()} is the same as the class loader for its element
* type; if the element type is a primitive type, then the array class has no
* class loader. 数组的类加载器类型和其元素的类加载器类型一致





其实只要重写findClass()方法,因为loadClassData()是被findClass()方法调用的。
自定义ClassLoader
package jvm.classloader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class DefineClassLoader extends ClassLoader { /* * ClassLoader的两个构造器: * protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); } protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } */ public DefineClassLoader() { super(); } private String path; @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] b = loadClassData(name); System.out.println("name:"+name); return defineClass(name, b, 0, b.length); } //传过来的是可能是jvm.classloader.MyClass private byte[] loadClassData(String name) { FileInputStream fis = null; ByteArrayOutputStream output = null; // StringBuilder sb = new StringBuilder(); byte[] result = null; try { //需要转换成路径格式 jvm\classloader\MyClass if(path == null) { System.out.println("Sys"); fis = new FileInputStream(dotToSlash(name)+".class"); }else { System.out.println("Path:"+path+".class"); name = path+name.substring(name.lastIndexOf(".")+1)+".class"; System.out.println("My:"+name); fis =new FileInputStream(name); } output = new ByteArrayOutputStream(); byte[] bytes = new byte[10]; int line = 0; if((line=fis.read(bytes))!=-1) { // String str = new String(bytes,0,line); // sb.append(str); output.write(bytes, 0, line); } // result = sb.toString().getBytes(); result = output.toByteArray(); System.out.println("result:"+result); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { try { if(fis!=null) fis.close(); if(output!=null) output.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return result; } private String dotToSlash(String str) { return str.replace('.', '\\'); } public static void main(String[] args) throws Exception { // TODO Auto-generated method stub DefineClassLoader classLoader = new DefineClassLoader(); classLoader.path = "C:\\"; Class clz = classLoader.loadClass("jvm.classloader.MyClass"); ClassLoader l = clz.getClassLoader(); System.out.println(l); } } // //class MyClass{ // public void method() { // System.out.println("Hello!"); // } //}

调用流程:loadClass()-->去调用ClassLoader里面的loadClass()方法-->
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }
以下代码用到了递归:
先去寻找上一层引用(AppLoader->ExtLoader->BootStrapLoader),如果这些都没法加载,才会使用自定义的加载器去加载。
先一层一层地往上找,一直找到根加载器,如果根加载器有那么直接返回,如果没有,再返回扩展加载器加载的结果,如果还没有再返回App/Sys加载器的结果,还是没有再返回自定义加载器的返回结果。
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }



public abstract class ClassLoader { private static native void registerNatives(); static { registerNatives(); } // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. private final ClassLoader parent; /** * Encapsulates the set of parallel capable loader types. */

浙公网安备 33010602011771号