Java——类的加载,类加载器,类加载器的双亲委托模式,类加载器的作用

  1. 类的加载
    (1)加载:把字节码读取到内存中
    (2)连接:
    验证:确保加载的类信息符合JVM规范;准备:为类变量分配内存并为非final类变量默认初始值,如果是final的静态常量,直接赋常量值,这些内存都将在方法去中分配;解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
    验证,准备完成后,在方法区中已经有一个能够代表当前类的Class对象
    (3)类的初始化:大多数情况下和类的加载一起完成,有时不是

触发类初始化的操作(类的加载包含类的初始化一起完成):
(1)当虚拟机启动,先初始化main方法所在的类
(2)当初始化一个类,如果其父类没有初始化,则会先初始化它的父类
(3)new一个对象
(4)使用一个类的静态的成员(静态变量和静态方法),但这个静态的变量不能是final
(5)用java.lang.reflect包的方法对类进行反射调用
非触发类初始化的操作(类的加载不包含类的初始化一起完成):
(1)引用静态常量不会触发此类的初始化
(2)当访问一个静态域(静态变量,静态方法)时,只有真正声明这个域的类才会被初始化,即当通过子类引用父类的静态变量,静态方法时,不会导致子类初始化
(3)通过数组定义类引用,不会触发此类的初始化

  1. 类加载器

(1)引导类加载器/根类加载器(Bootstrap Classloader):加载java的核心库(JAVA_HOME/jre/lib/rt.jar等或sun.boot.class.path路径下的内容)是原生代码(C/C++)来实现的,并不继承自java.lang.ClassLoder,所以通过Java代码获取引导类加载值为null
(2)扩展类加载器(Extension ClassLoader)负责加载java的扩展库(JAVA_HOME/jre/ext/*.jar或java.ext.dirs路径下的内容),
(3)应用程序类加载器(Application Classloader)负责加载java应用程序类路径(classpath, java.class.path)下的内容
(4)自定义类加载器
什么情况下需自定义类加载器?
字节码需要加密和解密;字节码的路径不在常规路径,有自己特定的路径

  1. 获取某个类的类加载器
    先获取某个类的Class对象,再通过Class对象调用getClassLoader()方法获取类加载器对象

    public class ClientTest {
    	@Test
    	public void test1() throws ClassNotFoundException{
    		Class clazz=ClientTest.class; //获取类的class对象
    		ClassLoader loader = clazz.getClassLoader(); //获取它的类加载器对象  sun.misc.Launcher$AppClassLoader@106d69c
    		System.out.println(loader);
    		ClassLoader parent = loader.getParent();  
    		System.out.println(parent);  //sun.misc.Launcher$ExtClassLoader@c34f4d
    		ClassLoader parent2 = parent.getParent();
    		System.out.println(parent2);  //null 根类加载器(通过Java代码获取引导类加载值为null
    	}
    }
    
    Class clazz=String.class; 
    ClassLoader loader = clazz.getClassLoader();
    System.out.println(loader);  //返回null
    
  2. java中类加载器的双亲委托模式
    类加载器设计时,这四种类加载器是有层次结构的,但是层次结构不是通过继承关系来实现,而是通过组合方式来实现,通过getParent()获取“父加载器”
    双亲委托模式起到安全的作用,保证核心类库的类不会被替换掉,如何实现?
    当应用程序类加载器接到某个类的任务时,会先在内存中搜索这个类是否加载过,如果加载过就返回这个类的Class对象,不去加载;如果没找到,会把这个任务提交给“父加载器”
    当扩展类加载器接到某个类的任务时,会先在内存中搜索这个类是否加载过,如果加载过就返回这个类的Class对象,不去加载;如果没找到,会把这个任务提交给“父加载器”
    当引导类加载器接到某个类的任务时,会先在内存中搜索这个类是否加载过,如果加载过就返回这个类的Class对象,不去加载;如果没找到,会在它负责的范围内尝试加载,如果可以找到,那么返回这个类的Class对象,然后结束;如果没有找到,那么会把这个任务往回传,让“自类加载器”扩展类加载器去加载
    “子类加载器”扩展类加载器接到“父加载器”返回的任务后,去它负责的范围内加载,如果可以找到,那么返回这个类的Class对象,然后结束;如果没有找到,那么会把这个任务往回传,让“自类加载器”扩展类加载器去加载
    “子类加载器”应用程序类加载器接到“父加载器”返回的任务后,去它负责的范围内加载,如果可以找到,那么返回这个类的Class对象,然后结束;如果没有找到,那么就报错ClassNotFoundException或java.lang.NoClassDefError

  3. 类加载器的作用
    加载类;可以加载“类路径下”的资源文件
    ClassLoader类加载器的类型:getResourceAsStream(“资源文件的路径名”)
    SourceFolder:源代码文件夹,一般会用一个名为config的SourceFolder来装配置文件;在根目录下创建的SourceFolder文件相当于src文件
    //jdbc.properties在src目录下

    @Test
    public void test3() throws IOException{
    	Properties pro=new Properties();
    	Class clazz=ClientTest.class;
    	ClassLoader loader = clazz.getClassLoader();
    	InputStream in = loader.getResourceAsStream("jdbc.properties");
    	pro.load(in);
    	System.out.println(pro);
    }
    
    //in.properties在src下的包下
    @Test
    public void test4() throws IOException{
    	Properties pro=new Properties();
    	Class clazz=ClientTest.class;
    	ClassLoader loader = clazz.getClassLoader();
    	InputStream in = loader.getResourceAsStream("Test1/in.properties");
    	pro.load(in);
    	System.out.println(pro);
    }
    //out.properties在项目根路径下
    @Test
    public void test5() throws FileNotFoundException, IOException{
    	Properties pro=new Properties();
    	pro.load(new FileInputStream("out.properties"));
    	System.out.println(pro);
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值