本篇内容:
- 1、java反射实现
- 2、java类加载器ClassLoader
- 3、java反射机制
一、java反射代码
1、创建java实体类
public class Car {
private String brand;
private String color;
private int maxSpeed;
public Car() {
}
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void getData() {
System.out.println("Car{" +
"brand='" + brand + '\'' +
", color='" + color + '\'' +
", maxSpeed=" + maxSpeed +
'}');
}
// 省略get,set方法
}
2、测试类:通过反射获取java对象
public class CarTest {
public static Car initByDefaultConst() throws Exception {
//得到ClassLoader对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//通过java全路径名称获取java实体对象
Class aClass = loader.loadClass("com.demo.Car");
//获取反射对
Constructor constructor = aClass.getDeclaredConstructor(null);
//通过构造函数实例化java对象
Car car = (Car) constructor.newInstance();
//通过类对象获取实体的setter方法
Method setBrand = aClass.getMethod("setBrand", String.class);
setBrand.invoke(car, "雷克萨斯 ES");
Method setColor = aClass.getMethod("setColor", String.class);
setColor.invoke(car, "银色");
Method setMaxSpeed = aClass.getMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 300);
return car;
}
@Test
public void getCar() throws Exception {
Car car = initByDefaultConst();
car.getData();
}
}
二、java的类加载器ClassLoader
1、工作机制
- 寻找类的字节码文件并构造出类在JVM内部表示对象的组件。
类加载器把一个类加入jvm的步骤
-
1、装载:查找和导入Class文件
-
2、连接:执行校验、准备和解析步骤(解析步骤是可选的)
-
2.1、校验:检查载入Class文件数据的准确性
-
2.2、准备:给类的静态变量分配存储空间
-
2.3、解析:将符号引用转换成直接引用
-
3、初始化:对类的静态变量,静态代码块执行初始化工作
-
类的装载构造由ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统组件,负责在运行时查找和装入class字节码文件
-
JVM在运行时会产生3个ClassLoader:根装载器,ExtClassLoader(扩展类装载器),APPClassLoader(应用类装载器)
2、测试jvm中3个类的关系
@Test
public void getJVM(){
ClassLoader loader = Thread.currentThread().getContextClassLoader();
System.out.println("current: "+loader);
System.out.println("current: "+loader.getParent());
System.out.println("current: "+loader.getParent().getParent());
}
- 输出
current: sun.misc.Launcher$AppClassLoader@18b4aac2
current: sun.misc.Launcher$ExtClassLoader@776ec8df
current: null
- 从输出内容可知:
- 1、ClassLoader就是AppClassLoader,
- 2、ClassLoader的父类是ExtClassLoader
jvm装载类时使用“全盘负责委托机制”。
- 1、“全盘负责”:是指当一个ClassLoader装载一个类时,除非显示地使用另一个ClassLoader,该类所依赖及引用的类也由这个类载入。
- 2、“委托机制”:是指先委托父类装载器找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标。
3、ClassLoader的重要方法
1、Class loadClass(String name)
- name参数指定类装载需要的类名,必须使用全路径名称。重载方法Class loadClass(String name,boolean resolve)resolve参数告诉类装载器是否需要解析该类,在初始化前要考虑进行解析的工作,单不是所有的类都需要解析。
2、Class defuneClass(String name, byte[ ] b, int off, int len)
- 将类文件的字节数组转换成JVM内部的Class对象,字节数组可以从本地文件系统,远程网络获取。参数name为全路径类名。
3、Class findSystemClass(String name)
- 将本地文件系统载入Class文件,如果本地文件不存在该Class文件,将抛出ClassNotFoundException,该方法是JVM默认使用的装载机制
4、ClassLoader getParent()
- 获取父类装载器,处理根装载器外所有的类装载器只有一个父装载器。ExtClassLoader的父装载器是根装载器,因为跟装载器不是java语言编写,无法获取
每个类在JVM中都拥有一个对应的Class对象,它提供了类结构信息的描述。Class对象是在装载类时由JVM通过调用类装载器中的defineClass()自动构造。
三、java反射机制
- Class反射对象描述类语义结构,可以从Class对象中获取构造函数,成员变量,方法类等元素的反射对象,并以编程的方式通过这些反射对象对目标进行操作。
- java主要反射类:Constructor,Method,Field
1、Constructor: 类的构造函数反射类
- 通过Class#getConstructor()可以获取类的所有构造函数反射对象数组。
- Constructor的一个主要方法是newInstance(Object[ ] initargs),通过此方法可以创建一个对象类的实例
2、Method:类方法的反射类
- 通过Class#getDecrlaredMethods()可以获取类的所有方法反射类对象数组Method[ ]。
- Method最主要的方法是incoke(Object obj,Object[ ] args),obj表示操作的目标对象,args为方法参数
Method用于获取类信息方法
- Class getReturnType():获取方法的返回值类型
- Class[ ] getParameterTypes():获取方法入参类型数组
- Class[ ] getExceptionType():获取方法异常类型数组
- Annotation[ ] [ ] getParameterAnnotations():获取方法的注解信息
3、Field:类的成员变量的反射类
- 通过Class#getDeclaredFields()可以获取类的成员变量反射对象数组。
- Class#getDeclaredField(String name):可以获取某个特定名称的成员变量反射对象
- 主要方法:set(Object obj,Object value),obj表示操作的目标对象,value为设置值
- 如果成员变量为基础类型,可以使用Fiel提供的带类型名的值设置方法:setBoolean(Object obj,boolean value),setInt(Object obj,int value)
4、私有方法反射
- java为包提供了Package反射类,有注解反射类:AnnotatedElement反射类。
- java的反射体系保证了可以通过程序化的方式访问目标类中所有的元素,对private或protected成员变量和方法,只要JVM安全机制允许也可以通过反射调用
4.1、定义实体类
public class PrivateCar {
private String color;
protected void getData() {
System.out.println("the color is :" + color);
}
}
4.2、测试类
public class PrivateCarTest {
@Test
public void getCar() throws Exception {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.demo.PrivateCar");
PrivateCar car = (PrivateCar) clazz.newInstance();
Field colorField = clazz.getDeclaredField("color");
colorField.setAccessible(true); //取消java语言访问检查
colorField.set(car,"银色");
Method method = clazz.getDeclaredMethod("getData", null);
method.setAccessible(true); //取消java语言访问检查
method.invoke(car,null);
}
}
注意:
- 访问private或protected修饰的对象或方法需要调用setAccessible(boolean access)取消java语言检查,否则抛出异常。
demo代码地址
https://github.com/brusion/brusion-code/tree/master/demo-java/03%20-%20demo%20-%20spring/spring-study-4x/01-ioc/01-ioc-java
网友评论