类装载器——ClassLoader

       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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值