一、反射技术
反射:从字节码文件获取信息并进行操作
二、反射的原理
对类进行编译会生成字节码文件
第一次主动使用实体类时,会把字节码文件加载到方法区里,并且生成字节码文件对应的对象,该对象是Class类型。
Class类:不论是哪个字节码文件,加载到方法区里都会生成的一个对应的对象,这些对象都有一些共同的特征或行为,例如类定义,类名,构造,方法,属性等特征。根据这些共同特征,向上抽取了一个类,叫Class类。Class类提供了一些功能,对于字节码文件对应的对象,可以去调用Class类的功能去获得他们对应的字节码文件中的所有数据信息。
三、获取Class的几种方式
package com.gaj.day05;
public class Student {
private int no;
public String name;
public Student(){
System.out.println("无参构造");
}
public Student(int no, String name) {
this.no = no;
this.name = name;
System.out.println("带参构造:" + this.no + "," + this.name);
}
public void method(){
System.out.println("无参方法");
}
public String function(String str, int num){
return "代参方法:" + str + ":" + num;
}
}
package com.gaj.day05;
/**
* 对字节码文件进行操作
* 3种方式获取Class
* @author Jan
*
*/
public class Demo1 {
public static void main(String[] args) {
// 方式一:明确知道返回类型
// 代码中需要直接用上该类
Class<Student> c1 = Student.class;
// 方式二:创建一个对象并getClass
// 返回类型是Student以及Stundent的子类型
// 代码中需要直接用上该类并且创建了对象
Class<? extends Student> c2 = new Student().getClass();
// 方式三:字符串:全限定名 会抛异常
// 返回类型不确定
// 推荐,作为字符串的形式加载,更灵活
try {
Class<?> c3 = Class.forName("com.gaj.day05.Student");
System.out.println(c3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1);
System.out.println(c2);
}
}
三、反射的获取和操作
1、获取/操作属性
package com.gaj.day05;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* Field
* 对属性的访问和操作
* @author Jan
*
*/
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {
Class<?> c = Class.forName("com.gaj.day05.Student");
// 获取所有public属性
Field [] fs = c.getFields();
// 获取所有访问权限的属性
fs = c.getDeclaredFields();
for (Field field : fs) {
// 获得属性名称
System.out.println(field.getName());
// 获得类型
System.out.println(field.getType());
// 获得访问权限
// field.getModifiers()是数字,需要通过Modifier的tostring方法进行转换
System.out.println(Modifier.toString(field.getModifiers()));
}
// 获得单个属性
Field f = c.getDeclaredField("name");
// 创建一个对象
Object obj = c.newInstance();
// 给属性赋值
f.set(obj, "Tom");
// 获取这个属性
System.out.println(f.get(obj));
// 设置private属性 会抛出异常
f = c.getDeclaredField("no");
// 赋予修改权限
f.setAccessible(true);
f.set(obj, 1);
System.out.println(f.get(obj));
}
}
2、获取/操作方法
package com.gaj.day05;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Method
* 对方法的访问和操作
* @author Jan
*
*/
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, NoSuchMethodException, SecurityException {
Class<?> c = Class.forName("com.gaj.day05.Student");
Method [] ms = c.getDeclaredMethods();
for (Method method : ms) {
// 获得名称
System.out.println(method.getName());
// 获得返回值类型
System.out.println(method.getReturnType());
// 获得参数类型 getParameterTypes返回一个数组
System.out.println(Arrays.toString(method.getParameterTypes()));
}
// 单个方法
Method m = c.getDeclaredMethod("method");
// 创建对象
Object obj = c.newInstance();
// 调用方法
m.invoke(obj);
// 带参方法
m = c.getDeclaredMethod("function", String.class, int.class);
System.out.println(m.invoke(obj, "hello", 999));
}
}
3、获取/操作构造
package com.gaj.day05;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
/**
* Constructor
* 对构造的访问和操作
* @author Jan
*
*/
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, NoSuchMethodException, SecurityException {
Class<?> c = Class.forName("com.gaj.day05.Student");
Constructor<?> [] crs = c.getDeclaredConstructors();
for (Constructor<?> constructor : crs) {
System.out.println(Arrays.toString(constructor.getParameters()));
}
// 获得无参构造
Constructor<?> cr = c.getDeclaredConstructor();
cr.newInstance();
// 带参构造
cr = c.getDeclaredConstructor(int.class, String.class);
cr.newInstance(22, "Tom");
}
}