JAVA类加载器,反射,双亲委派

0x01 类加载器:

类的生命周期:加载(类加载器负责)------->连接(验证类是否合法,分配类静态变量内存空间并赋值,解析地址)---->初始化--->使用(调用静态方法,new实例)------>卸载

类加载器的作用:加载java文件到JVM

常见的类加载器:

(1)Bootstrap ClassLoader(引导类加载器)---顶层类加载器--由c++实现

(2)Extension ClassLoader(扩展类加载器)---加载jre

(3)App ClassLoader(系统类加载器)---代码默认的类加载器

(4)CustomClassLoader----自定义的类加载器------重写findClass等,继承ClassLoader

引用简书大佬一张图:

注:class forname实际也是调用类加载器加载class

一段代码领略他们之间的关系

debug 至getClassLoader方法具体实现,78行调用getClassLoader0

getClassLoader0返回了classLoader

运行结果

重点:

ClassLoader类:

其主要的几个方法:

  1. loadClass(加载指定的Java类)
  2. findClass(查找指定的Java类)
  3. findLoadedClass(查找JVM已经加载过的类)
  4. defineClass(定义一个Java类)
  5. resolveClass(链接指定的Java类)

Class.forname:

静态看一下forname的实现

Class<?> caller = Reflection.getCallerClass();//返回当前调用类

forName0(className, true, ClassLoader.getClassLoader(caller), caller);//返回当前类的类加载器,forName0为native方法,ClassLoader.getClassLoader具体实现

跟进getClassLoader0, 发现具体方法与上面的一个demo一样,都是返回当前类加载器

 

Class.forName与类加载器的区别与联系:

// 反射加载Memory示例
Class.forName("com.test.Memory");

// ClassLoader加载Memory示例
this.getClass().getClassLoader().loadClass("com.test.Memory");

    区别:Class.forName("类名")默认会初始化被加载类的静态属性和方法,如果不希望初始化类可以使用Class.forName("类名", 是否初始化类, 类加载器),而ClassLoader.loadClass默认不会初始化类方法

   联系:Class.forName本质也是通过调用类加载器实现

Thread.currentThread().getContextClassLoader():

获取当前线程的ClassLoader

运行结果

sun.misc.Launcher$AppClassLoader@18b4aac2

 具体方法

其中contextClassLoader为当前填充的ClassLoader

 

0x02  反射

       运行状态中(不是编译时),对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java的语言的反射机制

     个人理解,反射用法,class forname调用类加载器加载类,newInstance实例化对象,getMethod获取方法,invoke调用方法

    在开发漏洞验证框架为了可以将类路径参数化调用java类,比较方便,但是比较消耗内存,使用记录

demo:

运行结果:

Class.forName默认初始话静态变量静态方法

debug:

强制步入 :发现也是调用了当前了类的类加载器

 

0x03 双亲委派

    某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次追溯,直到最高的爷爷辈的。如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载;

     双亲委托机制的最大的好处就是可以确保是安全的。这种机制保证了不会出现用户自己能定义java.lang.Object类的情况出现。类加载器除了用于加载类,也是安全的最基本屏障

双亲委派关键代码:

 代码实现:ClassLoader的loadClass()方法中,先检查是否已经被加载过,若没有加载则调用父类加载器的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载失败,则抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载。

demo:

如果自己实现了java.lang.Class,跑起来会跑错,防止自己定义java.*等一系列代码

 

 

参考文章:

https://www.jianshu.com/p/8df45255c4bd

https://javasec.org/javase/ClassLoader/

https://blog.csdn.net/qq_36582604/article/details/81100501

https://www.cnblogs.com/cl-rr/p/9081817.html

https://www.jianshu.com/p/554c138ca0f5

https://www.cnblogs.com/jimoer/p/9185662.html

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值