zoukankan      html  css  js  c++  java
  • 深入分析ClassLoader

    首先介绍下ClassLoader:
    ClassLoader顾名思义就是类加载器,负责将Class加载到JVM中,事实上ClassLoader除了能将Class加载到JVM中之外,还有一个重要的作用就是审查每个类应该有谁加载,ClassLoader是一个父优先的等级加载机制。ClassLoader除了上述两个作用外还有一个任务就是将Class字节码重新解析成JVM统一要求的对象格式-----------由此本文可以划分成三点

    1. ClassLoader类结构分析
      1. ClassLoader常用的方法
      输入图片说明
      1,defineClass():用来将byte字节流解析成JVM能够识别的Class对象
      2,findClass():用来子类扩展的方法,目的是为了寻找类
      3,loadClass():加载类,这里就可以动态加载了,程序运行的时候加载
      4,resolveClass():这个方法是用来链接这个类
      JDK给我们提供了可以扩展的,也就是我们可以自定义的类加载器URLCLassLoader,比较方便

       2. ClassLoader的等级加载机制      
      

    输入图片说明

    1,BootStrap ClassLoader: 
    

    这是一个引导类加载器,首先声明一下虽说在类的结构中可以看到这个类,但是这个类只有Class文件,据了解这个类是通过C++编写的,这也就是ExtClassLoader的父类为空的原因。引导类负责加载JDK的jre下的类库,例如rt.jar

    2,ExtClassLoader:
    

    这是一个扩展类加载器,加载bin目录下的ext文件夹下的jar包,不多说

     3,AppClassLoader:
    

    这个类加载器就是我们自定义的类,例如我们的这个方法getSystemClassLoader()作为父加载器,这个加载器也就是AppClassLoader。

     4,加载类过程总结:
    

    看了很多资料都是什么双亲委托加载机制,具体我也不是很清楚,可以我太low,但是我个人的理解就是,当加载一个类的时候:首先检查这个类是否已经被自己加载过,如果已经加载过,就拒绝本次加载,如果没有加载过,就会抛给他的父类,然后父类在检查是否加载,然后在抛给父类,直到全部检查完都没有发现这个类被加载,那么就有意思了,因为每一个类加载器都有自己的加载范围,然后开始判断,父类不加载类,那么就开始向下寻找这个类的加载器,然后这个类被加载,也就是先向上检查是否加载,其次向下看是否可以加载!--------------------这里有一个讲解,来帮助理解,如果我们自己写了一个java.lang.String,那么类加载器就先去加载jdk下的java.lang.String.遇到我们自己定义的类就不会加载了,这也就是java.lang.Object首先被加载,父类加载会防止我们破坏干扰jre的正常运行,导致类结构被破坏

    这里是类关系的代码

    public class ClassA {
    }
    public class ClassB {
    }
    public class ClassTest {
    	public static void main(String[] args) {
    		//演示 我們的類加載器
    		System.out.println("ClassTest-------------ClassLoader:"+ClassTest.class.getClassLoader());
    		System.out.println("ClassTest.Parent------ClassLoader:"+ClassTest.class.getClassLoader().getParent());
    		System.out.println("ClassTest.GrandFather-ClassLoader:"+ClassTest.class.getClassLoader().getParent().getParent());
    		
    		//用户自定义的类加载   都是通过AppClassLoader加载
    		System.out.println(ClassA.class.getClassLoader());
    		System.out.println(ClassB.class.getClassLoader());
    		//结论就是----------当两个类名称不同,那么这两个类就不相同
    	}
    }
    

    打印结果

    ClassTest-------------ClassLoader:sun.misc.Launcher$AppClassLoader@73d16e93
    ClassTest.Parent------ClassLoader:sun.misc.Launcher$ExtClassLoader@15db9742
    ClassTest.GrandFather-ClassLoader:null
    sun.misc.Launcher$AppClassLoader@73d16e93
    sun.misc.Launcher$AppClassLoader@73d16e93
    
    1. 如何判断两个类相同
    • 类名称不同
    这里就不需要介绍了,只要类名不同,那么类肯定也不同
    
    • 包名称不同
    package me.classloader.classpackage;
    
    public class String {
    
    }
    
    
    package me.classloader.classpackage;
    
    import org.junit.Test;
    
    public class ClassTest {
    	@Test
    	public void classTest(){
    		//这里是  BootStrap ClassLoader-------因此返回Null
    		System.out.println(java.lang.String.class+"------classLoader:"+java.lang.String.class.getClassLoader());
    		//这里 我们自定义的类        被AppClassLoader 加载
    		System.out.println(String.class+"--------ClassLoader:"+String.class.getClassLoader());
    		//很明显这两个类是不同的
    	}
    }
    
    这里可以得到我们的包名可以引起 两个类不是同一个类,并且,这里JVM就近调用一个类先调用的同包下的类
    
    • 类加载器不同
    package me.classloader.classloader;
    
    public class Demo {
    	private Demo demo;
    
    	public void setDemo(Demo demo) {
    		this.demo = demo;
    	}
    	
    }
    
    package me.classloader.classloader;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    //自己写的ClassLoader
    public class MyClassLoader extends ClassLoader {
    
    	private String classPath;// 类路径
    
    	public MyClassLoader() {
    	}
    
    	public MyClassLoader(String classPath) {
    
    		this.classPath = classPath;
    	}
    
    	@Override
    	protected Class<?> findClass(String name) throws ClassNotFoundException {
    
    		byte[] classDate = getDate(name);
    		if (classDate == null) {
    			throw new ClassNotFoundException();
    		} else {
    			return defineClass(name, classDate, 0, classDate.length);
    		}
    	}
    
    	// 将 class 文件转化成字节流
            //className是类名称---权限定名
    	private byte[] getDate(String className) {
    		// 将XX.XX.java --------->XX/XX/java.class
    		String path = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
    		try {
    			InputStream is = new FileInputStream(path);
    			ByteArrayOutputStream stream = new ByteArrayOutputStream();
    			byte[] buffer = new byte[1024];
    			int num = 0;
    			while ((num = is.read(buffer)) != -1) {
    				stream.write(buffer, 0, num);
    			}
    			return stream.toByteArray();
    
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return null;
    	}
    }
    
    package me.classloader.classloader;
    
    public class ClassTest {
    	public static void main(String[] args) throws Exception{
    		String classPath ="E:\javaprogram\java-exercise\classload\bin";
    		String className = "me.classloader.classloader.Demo";
    		ClassLoader appClassLoader = ClassTest.class.getClassLoader();
    		MyClassLoader myClassLoader = new MyClassLoader(classPath);
    		Class demo1 = appClassLoader.loadClass(className);
    		System.out.println(demo1.newInstance().getClass().getClassLoader());
    		Class demo2 = myClassLoader.findClass(className);
    		System.out.println(demo2.newInstance().getClass().getClassLoader());
            System.out.println(demo1.newInstance().getClass() ==demo2.newInstance().getClass());
    	}
    }
    
    测试结果
    sun.misc.Launcher$AppClassLoader@73d16e93
    me.classloader.classloader.MyClassLoader@6d06d69c
    false
    

    通过上面的代码,我们也知道了如何写一个类加载器,其实查看findClass()是ClassLoader提供的一个模板方法!

    总结:类加载器也是一个比较深的东西,例如servlet中jsp使用了热部署!其实就是类加载器的应用,可能动态代理也用到了类加载器,因为实际工作加载的是我们代理的类

  • 相关阅读:
    C# 字段 属性 方法 三霸主齐上阵
    C# 项目之总结,浓缩才是精华
    C# 语法 重中之重
    岁月流逝,C#成为我们IT精英永恒不变的经典
    pv:快餐厅4类职员正确并发运行的程序——用pv实现有向图的前驱关系哦!
    pv错题:用pv操作实现旅客,汽车之间的同步关系——北航2018考研计算机!!!!!!!!我还很不熟练,奋斗吧少年!!!!!!
    windows 的 DMA
    pv打卡:生产者消费者问题扩展——>南航2002pv习题哦
    冷门的OS知识:中断——这个我多大熟练qwq!
    Unix混合索引结构_文件系统_文件的组织_文件的物理结构_多级索引文件——>相关的小计算题!!!!!!重点重点重点!!!!!!
  • 原文地址:https://www.cnblogs.com/obesityspace/p/6258089.html
Copyright © 2011-2022 走看看