类装载器——ClassLoader

来源:互联网 发布:vip视频解析原理知乎 编辑:程序博客网 时间:2024/06/05 20:05

       Java语言允许通过程序化的方式间接对Class进行操作,Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数、属性和方法等。Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能,这就为使用程序化方式操作Class对象开辟了途径。


一、类装载器的工作机制:

       类装载器就是寻找类的字节码文件并构造出类在JVM内部表示对象的组件。在Java中,类装载器把一个类装入JVM,要经过以下步骤:

      1.装载:查找和导入Class文件

      2.链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的:

                    (1)  校验:检查载入Class文件数据的正确性。

                    (2)  准备:给类的静态变量分配存储空间

                    (3)  解析:将符号引用转为直接引用。

      3.初始化:对类的静态变量、静态代码块执行初始化工作。

      类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件。JVM在运行时会产生三个ClassLoader:根装载器、ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。其中,根装载器不是ClassLoader的子类,它使用C++编写,因此我们在Java中看不到它,根装载器负责装载JRE的核心类库,如JRE目标下的rt.jar,charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子类。其中ExtClassLoader负责装载JRE扩展目录ext中的JRE类包;AppClassLoader负责装载Classpath路径下的类包。

      这三个类装载器之间存在父子层次关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下,使用AppClassLoader装载应用程序的:

     ClassLoaderTest.java文件:

public class ClassLoaderTest {public static void main(String[] args) {ClassLoader loader=Thread.currentThread().getContextClassLoader();System.out.println("current loader:"+loader);System.out.println("parent loader:"+loader.getParent());System.out.println("grandparent loader:"+loader.getParent().getParent());}}

输出结果:

current loader:sun.misc.Launcher$AppClassLoader@73d16e93
parent loader:sun.misc.Launcher$ExtClassLoader@15db9742
grandparent loader:null

     通过以上的输出信息,我们知道当前的ClassLoader是AppClassLoader,父ClassLoader是ExtClassLoader,祖父ClassLoader是根类装载器,因为在Java只无法获得它的句柄,所以返回null。

二、Java反射机制

     Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义,下面是最主要的三个反射类:

     (1)Constructor:类的构造函数反射类

     (2)Method:类方法的反射类

     (3)Field:类的成员变量的反射类

     反射类中的各种方法参考API文档中的java.lang.Class

例子:

Car.java文件:

public class Car {    private String color;    protected void introduce(){        System.out.println("color:"+color);    }}

ReflectTest.java文件:

import java.lang.reflect.Field;import java.lang.reflect.Method;public class ReflectTest {public static void main(String[] args) throws Exception{//1.通过类加载器加载Class文件ClassLoader loader=Thread.currentThread().getContextClassLoader();Class clazz=loader.loadClass("com.reflect.Car");//2.获取Car对象Car car=(Car)clazz.newInstance();//3.返回 Field 对象的一个数组,这些对象反映此 Class对象所表示的类或接口所声明的所有字段Field colorField=clazz.getDeclaredField("color");//4.取消Java语言访问检查以访问private变量colorField.setAccessible(true);//为成员变量赋值colorField.set(car, "红色");//5.返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法Method driveMtd=clazz.getDeclaredMethod("introduce",(Class[])null);//取消Java语言访问检查以访问public变量driveMtd.setAccessible(true);//6.对带有指定参数的指定对象调用由此 Method 对象表示的底层方法driveMtd.invoke(car,(Object[])null);}}

运算结果:

color:红色

注:在访问private、protected成员变量和方法时必须通过setAccessible(boolean access)方法取消Java语言检查,否则将抛出  illegalAccessException。如果JVM的安全管理器设置了相应的安全机制,调用该方法将抛出SecurityException

0 0
原创粉丝点击