[置顶] 黑马程序员_类加载器和代理

时间:2023-02-17 17:14:50
----------------- android培训、java培训、期待与您交流! ----------

  • ava虚拟机中可以安装多个类加载器,系统默认三个主要 类加载器,每个类负责加载特定位置的类: BootStrap,ExtClassLoader,AppClassLoader
  • 类加载器也是Java类,因为其他是java类的类加载器本⾝身 也要被类加载器加载,显然必须有第⼀一个类加载器不是不 是java类,这正是BootStrap
  • Java虚拟机中的所有类装载器采⽤用具有父子关系的树形结 构进⾏行组织,在实例化每个类装载器对象时,需要为其指 定⼀一个⽗父级类装载器对象或者默认采⽤用系统类装载器为其父级类加载

1. 逐一编写如下代码来说明放置在不同位置的类确实由不同的类加载器加载的:

System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName()); //将上面语句的测试类改为System则抛NullPointerException,这两个类存放位置不同

System.out.println(System.class.getClassLoader().getClass().getName()); 改为System.out.println(System.class.getClassLoader());打印的结果为null。

2.用下面的代码让查看类加载器的层次结构关系ClassLoader loader = ClassLoaderTest.class.getClassLoader();

//打印出当前的类装载器,及该类装载器的各级父类装载器 

while(loader != null){

System.out.println(loader.getClass().getName()); 

loader = loader.getParent();

}

[置顶]        黑马程序员_类加载器和代理

当Java虚拟机要加载⼀一个类时,到底派出哪个类加载器去加载 呢?

  • 首先当前线程的类加载器去加载线程中的第⼀一个类。 如果类A中引⽤用了类B,Java虚拟机将使⽤用加载类A的类装载器来加载类
  • 还可以直接调⽤用ClassLoader.loadClass()⽅方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,⼜又先委托给其上级类加载器。

  • 当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不 了,则抛ClassNotFoundException,不是再去找发起者类加载器的⼉儿 ⼦子,因为没有getChild⽅方法,即使有,那有多个⼉儿⼦子,找哪⼀一个呢?
  • 对着类加载器的层次结构图和委托加载原理,解释先前将 ClassLoaderTest输出成jre/lib/ext⺫⽬目录下的itcast.jar包中后,运⾏行结果为 ExtClassLoader的原因。

每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模 式。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进 行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。

 

[置顶]        黑马程序员_类加载器和代理

使用代理的好处:
          
          
  • 要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情
  • JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。 
  • JVM生成的动态类必须实现⼀一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。 
  • CGLIB库可以动态生成一个类的子类⼀一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。 


代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理⽅方法中的如下四个位置加上系统功能代码:

  • 在调用目标方法之前
  • 在调用目标方法之后
  • 在调用目标方法前后
  • 在处理目标方法异常的catch块中