Java深度理解——反射

反射是Java独有的技术,是Java技术的显著特点
反射是指对于任何一个类,在运行时都可以直接得到这个类的全部成分(构造器对象,成员变量对象,方法对象等)
反射的核心思想和关键就是得到编译以后的class文件对象
获取class类对象
Class:字节码文件的类型
Constructor:构造器的类型
Field:成员变量的类型
Method:方法的类型
反射技术的第一步永远是先得到Class对象,有三种方式获取:
- 类名.class
- 通过类的对象.getClass()方法
- class.forName(“类的全限名”)
//类名.class
Class c1 = Student.class;
//对象.getClass()
Student s = new Student();
Class c2 = s.getClass();
//Class.forName("类的全限名")
Class c3 = Class.forName("stage03.reflectDemo.Student");
Class类下的方法:
-
String getSimpleName(); 获得类名字符串:类名
-
String getName(); 获得类全名:包名+类名
-
T newInstance(); 创建class对象关联类的对象,其实底层也是调用无参构造器,已被淘汰
System.out.println(c1.getSimpleName());//获取简名 System.out.println(c1.getName());//获取全限名 Student s1 = (Student) c1.newInstance();//调用无参构造器得到对象,已经过时
获取Constructor构造器对象
通过class类型获取构造器:
Constructor getConstructor(Class...parameterTypes)
根据参数匹配获取某个构造器,只能拿到public
修饰的构造器Constructor getDeclaredConstructor(Class...parameterTypes)
根据参数匹配某个构造器,只要申明就可以定位,不必关心构造器权限修饰符Constructor[] getConstructors()
获取所有的构造器,只能拿public
修饰的构造器Constructor[] getDeclaredConstructors()
:获取所有的构造器,不用关心权限修饰符
Constructor
的API:
T newInstance(Object...initargs)
:创建对象,注入构造器需要的数据void setAccessible(true)
修改访问权限,true代表暴力反射攻破权限,false表示保留不可访问权限(暴力反射),注意:是一次性打开
public void createObject() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取class类对象
Class c = Student.class;
//定位有参数构造器对象
Constructor constructor = c.getDeclaredConstructor(String.class,int.class);
//暴力打开私有构造器的访问权限
constructor.setAccessible(true);
//通过有参数构造器初始化对象并返回
Object swk = (Student)constructor.newInstance("张三", 18);
System.out.println(swk);
}
/**************Student类*************************/
package stage03.reflectDemo;
import lombok.Data;
/**
* @author YJL
*/
public class Student {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
System.out.println("无参构造器执行");
}
private String name;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private int age;
private Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造器执行");
}
}
执行结果:
获取成员变量Field
Field getField(String name);
根据成员变量名获取对应Field对象,只要申明了就可以得到Field getDeclaredField(String name);
根据成员变量名获得对应Field对象,只要申明了就可以得到Field[] getFields();
根据获得所有成员变量对应的Field对象,只能获得public的Field[] getDeclaredFields();
根据获得所有成员变量对应的Field对象,只要申明了就可以得到
实例成员变量,静态成员变量,常量全部可以获取到
给成员变量取值和赋值
void set(Object obj,Object Value);
给对象注入某个成员变量数据(参数一:被赋值的对象,参数二:该成员变量的值)Object get(Object Obj);
获取对象的成员变量的值;void setAccessible(true)
:暴力反射Class getTye
:获取属性的类型,返回Class对象String getName()
:获取属性的名称。
eg:
@Test
public void setField() throws Exception {
//获取Class对象
Class<Student> c = Student.class;
//获取成员变量
Field name = c.getDeclaredField("name");
//先创建对象
Student student = new Student();
//暴力反射
name.setAccessible(true);
//赋值
name.set(student,"张三");
System.out.println(student.getName());
}
/****************Studnet类**********************/
package stage03.reflectDemo;
import lombok.Data;
/**
* @author YJL
*/
public class Student {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
System.out.println("无参构造器执行");
}
private String name;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private int age;
private Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造器执行");
}
}
执行结果:
获取Method方法对象
-
Method getMethod(String name,Class...args)
根据方法名和参数类型获得相应的方法对象,只能获得public的 -
Method getDeclaredMethod(String name,Class...args)
根据方法名和参数类型获得相应的方法对象,包括private -
Method getMethods()
:获得类中所有的成员方法,返回数组,只能获得public修饰的且包含父类的 -
Method getDeclaredMethods()
:获得类中的所有成员方法对象,返回数组,获得苯类声明的所有方法 -
invoke(Object obj,Object...args)
:执行方法参数一:触发的是那个对象的方法执行
参数二:args:调用方法时传递的实际参数
@Test
public void getDeclaredMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//获取class类对象
Class<Student> c = Student.class;
//获取方法
Method study = c.getDeclaredMethod("study",String.class);
//暴力反射
study.setAccessible(true);
//创建对象
Student student = new Student();
//执行
study.invoke(student,"测试");
}
/*****************Student***************/
public class Student {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
System.out.println("无参构造器执行");
}
private String name;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private int age;
private Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造器执行");
}
private void study(String s){
System.out.println("方法执行");
}
执行结果:
反射的小应用:
暴力破解泛型的约束:
泛型只能在工作阶段编译,运行阶段就消失了,而反射工作在运行阶段
@Test
public void destroyGeneric() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
Class<? extends ArrayList> aClass = arrayList.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.invoke(arrayList,"测试");
System.out.println(arrayList);
}
运行结果: