Java中的反射和类装载器
来源:互联网 发布:java 静态变量 泛型 编辑:程序博客网 时间:2024/04/30 21:42
首先通过一个简单的例子看一下Java中的反射,如下,是一个Car类:
Car.java
public class Car { private String brand; private String color; private int maxSpeed; public Car(){System.out.println("init car!!");} public Car(String brand,String color,int maxSpeed){ this.brand = brand; this.color = color; this.maxSpeed = maxSpeed; } public void introduce() { System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed); } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; }}
通常我们可以使用如下方式创建Car的实例:
Car car = new Car();car.setBrand("红旗");或:Car car = new Car("红旗", "黑色");
我们也可以通过Java中的反射机制以更加通用的方式间接的操作目标类:
import java.lang.reflect.Constructor;import java.lang.reflect.Method;public class ReflectTest { public static Car initByDefaultConst() throws Throwable { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.baobaotao.reflect.Car");// Class clazz = Class.forName("com.baobaotao.beans.Car1"); Constructor cons = clazz.getDeclaredConstructor((Class[])null); Car car = (Car)cons.newInstance(); Method setBrand = clazz.getMethod("setBrand",String.class); setBrand.invoke(car,"红旗CA72"); Method setColor = clazz.getMethod("setColor",String.class); setColor.invoke(car,"黑色"); Method setMaxSpeed = clazz.getMethod("setMaxSpeed",int.class); setMaxSpeed.invoke(car,200); return car; } public static Car initByParamConst() throws Throwable{ ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.baobaotao.reflect.Car"); Constructor cons = clazz.getDeclaredConstructor(new Class[]{String.class,String.class,int.class}); Car car = (Car)cons.newInstance(new Object[]{"吉利TOPMIX","绿色",120}); return car; } public static void main(String[] args) throws Throwable { Car car1 = initByDefaultConst(); Car car2 = initByParamConst(); car1.introduce(); car2.introduce(); }}
如上,首先获取到当前线程的ClassLoader,然后通过指定全限定类装载Car类对应的反射实例,然后通过反射类对象获取Car的构造函数对象cons,然后通过构造函数对象的newInstance()方法实例化Car对象,后面通过Car的反射类对象的getMethod(String methodName, Class paramClass)方法获取属性的Setter方法对象,然后通过invoke(Object obj, Object param)方法调用目标类的方法,通过如上方法操作目标类的元信息。
反射机制的通用性在于,我们可以将这些信息以配置文件的方式提供,然后编写通用的代码来进行实例化操作。一些框架就使用到了这些技术。
接下来看一下类装载器的工作机制:
类装载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件,大致经过如下步骤:
- 装载:查找和导入Class文件
- 链接:执行教研、准备和解析步骤,解析步骤可选
- 校验:检查载入Class文件数据的正确性
- 准备:给类的静态变量分配存储空间
- 解析:讲符号引用转换成直接引用
- 初始化:对类的静态变量、静态代码块执行初始化工作。
JVM在运行时会产生三个ClassLoader:根装载器,ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。其中,根装载器不是ClassLoader的子类,它使用C++编写,因此在Java中看不到。
根装载器负责JRE的核心类库,ExtClassLoader和AppClassLoader都是ClassLoader的子类。其中ExtClassLoader负责装载JRE扩展目录的ext中的JAR类包;AppClassLoader负责装载Classpath路径下的类包。
这三个类装载器之间存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认使用AppClassLoader装载应用程序的类。
在JVM中出于安全考虑,装载类时使用“全盘负责委托机制”,委托机制是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。
即就是优先查找系统中已有的类,找不到才会使用用户自定义的类。
类实例、类描述对象以及类装载器之间的关系如下:
如上图,当类文件被装载并解析后,在JVM内将拥有一个对应的java.lang.Class类描述对象,该类的实例都拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联ClassLoader的引用。
通过反射机制还可以访问private和protected的成员变量和方法(当JVM安全机制允许),如下:
PrivateCar.java
public class PrivateCar { private String color; protected void drive(){ System.out.println("drive private car! the color is:"+color); }}
color变量和drive()方法都是私有的,通过类实例变量无法在外部访问,通过反射机制可以绕开这个限制,如下:
import java.lang.reflect.Field;import java.lang.reflect.Method;public class PrivateCarReflect { public static void main(String[] args) throws Throwable{ ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.baobaotao.reflect.PrivateCar"); PrivateCar pcar = (PrivateCar)clazz.newInstance(); //Field:类的成员变量的反射类 Field colorFld = clazz.getDeclaredField("color"); //取消Java语言访问检查以访问private变量 colorFld.setAccessible(true); colorFld.set(pcar,"红色"); Method driveMtd = clazz.getDeclaredMethod("drive",(Class[])null); //Method driveMtd = clazz.getDeclaredMethod("drive"); JDK5.0下使用 driveMtd.setAccessible(true); driveMtd.invoke(pcar,(Object[])null); }}
如上,在通过反射机制访问private、protected成员变量和方法时必须通过setAccessible(boolean access)方法取消Java语言检查,否则将抛出IllegalAccessException。如果JVM的安全管理器设置了相应的安全机制,调用该方法讲排除SecurityException。
- Java中的反射和类装载器
- java基础知识穿插:类装载器;反射
- Java进阶-Java中的类装载器和命名空间
- Java中的类装载和初始化模块
- Java中的类装载和初始化模块
- Java中的类装载器(ClassLoader)
- JAVA安全管理器和类装载器
- Java中的类装载机制、反射机制、JDK5.0版本新加入一些特性
- JAVA使用类装载器装载配置文件
- java类装载器
- java类装载器
- java 类装载器
- java类装载器
- Java 类装载器
- java 类装载器
- java 类装载器
- Java类装载器
- 传智播客Java web之 Servlet中的类装载器详解
- 如何评价 GitHub 发布的文本编辑器 Atom?
- jQuery异步提交form表单
- JAVA socket 进行十六进制报文交互测试
- ubuntu环境安装php7+ngnix+mysql
- linux下创建mysql用户
- Java中的反射和类装载器
- 命令行运行Unity脚本
- libCEF总结02字符串
- set命令简介
- EditText末尾添加删除小圆圈一键清空
- 薪酬模块生成工资条
- 并发网络架构
- Java读取Excel内容
- matlab 2015b compile java package 编译 jre1.8 jre1.7版本不一致的问题