反射
学习反射
反射就是:加载类、并允许以编程的方式解刨类中的各种成分(成员变量、方法、构造器)
-
反射第一步:加载类,获取类的字节码:class对象
获取Class对象的三种方法
-
Class c1 = 类名.class
-
调用Class提供方法:public static Class forName(String package);
-
Object调用的方法:public Class getClass(); Class c3 = 对象.getClass();
定义一个Student类
import lombok.Data; @Data public class Student { private String name; private int age; }
反射的第一步:获取类本身
public class RelectDemo1 { public static void main(String[] args) throws Exception { // 反射的第一步 //1.获取类本身:类.class Class c1 = Student.class; System.out.println(c1); //2.获取类本身:Class.forName("类的全类名") Class c2 = Class.forName("demo2reflect.Student"); System.out.println(c2); //3.获取类本身:对象.getClass() Student s = new Student(); Class c3 = s.getClass(); System.out.println(c3); System.out.println(c1 == c2);//true System.out.println(c2 == c3);//true } }
-
-
获取类的构造器:Constructor对象
Class提供了从类中获取构造器的方法。
方法 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 获取全部构造器(只拿取public修饰的) |
Constructor<?>[] getDeclaredConstryctors() | 获取全部构造器(只要存在就能拿到) |
Constructor getConstructor(Class<?>… parameterTypes) | 获取某个构造器(只能获取public修饰的) |
Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 获取某个构造器(只要存在就能拿到) |
获取类构造器的作用:依然是初始化对象返回
Constructor提供的方法 | 说明 |
---|---|
T newInstance(Object…intargs) | 调用次构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
定义Dog类对象用于测试
public class Dog {
private String name;
private int age;
private String hobby;
private Dog() {
}
private void eat(){
System.out.println("狗吃骨头");
}
public String eat(String name){
System.out.println("狗吃"+name);
return "狗说:谢谢!谢谢!";
}
private Dog(String name) {
this.name = name;
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
获取类的构造器并进行操作
@Test
public void getConstructorInfo() throws Exception {
//获取类的构造器对象并对进行操作
//1.反射的第一步:获取Class对象,代表拿到类
Class c1 = Dog.class;
//2.获取构造器对象
Constructor[] cons = c1.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
}
//3.获取单个构造器
Constructor con = c1.getDeclaredConstructor();
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
Constructor con2 = c1.getDeclaredConstructor(String.class, int.class);
System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");
//4.创建对象
//暴力反射:暴力反射,可以访问私有的属性,方法,构造器
con.setAccessible(true);//暴力反射
Dog d1 = (Dog) con.newInstance();
System.out.println(d1);//输出:Dog{name='null', age=0, hobby='null'}
Dog d2 = (Dog) con2.newInstance("小黑", 2);
System.out.println(d2);//输出:Dog{name='小黑', age=2, hobby='null'}
}
-
获取类的成员变量:Field对象
Class提供了从类中获取成员变量的方法。
方法 说明 public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的) public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到) public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的) public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到) 获取到成员变量的作用:依然是赋值,取值。
方法 说明 void set(Object obj,Object value) 赋值 Object get(Object obj) 取值 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射) 获取类的成员方法并进行操作
@Test public void getFieldInfo() throws Exception { //目标:获取类的成员变量信息 //1.获取Class对象 Class c1 = Dog.class; //2.获取成员变量对象 Field[] fields = c1.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName() + "(" + field.getType().getName() + ")"); } //3.获取单个成员变量对象 Field field = c1.getDeclaredField("hobby"); System.out.println(field.getName() + "(" + field.getType().getName() + ")"); Field field2 = c1.getDeclaredField("age"); System.out.println(field2.getName() + "(" + field2.getType().getName() + ")"); //4.获取成员变量的目的依然是取值和赋值 Dog d = new Dog("泰迪", 2); field.setAccessible(true); field.set(d, "睡觉"); System.out.println(d);//输出:Dog{name='泰迪', age=2, hobby='睡觉'} String hobby = (String) field.get(d); System.out.println(hobby);//输出:睡觉 }
-
获取类的成员方法:Method对象
Class提供了从类中获取成员方法的API
方法 说明 Method[] getMethods() 取类的全部成员方法(只能获取public修饰的) Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到) Method getMethod(String name,Class<?>…parameterTypes) 获取类的某个成员方法(只能获取public修饰的) Method getDeclaredMethod(String name,Class<?>…parameterTypes) 获取类的某个成员方法(只要存在就能拿到) 成员方法的作用:依然是执行
Method提供的方法 说明 public Object invoke(Object obj,Object…args) 触发某个对象的该方法执行 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射) 获取类的成员方法并进行操作
@Test public void getMethodInfo() throws Exception { //目标:获取类的成员方法信息 //1.获取Class对象 Class c1 = Dog.class; //2.获取成员方法对象 Method[] methods = c1.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName() + "(" + method.getParameterCount() + ")"); } //3.获取单个成员方法对象 Method m1 = c1.getDeclaredMethod("eat");//获取的是无参数的eat方法 Method m2 = c1.getDeclaredMethod("eat", String.class);//获取的是有参数的eat方法 System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")"); System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")"); Dog d = new Dog("泰迪", 4); m1.setAccessible(true); Object re1 = m1.invoke(d);//唤醒对象的eat方法,相当于d.eat(); System.out.println(re1);// Object re2 = m2.invoke(d, "骨头");//唤醒对象的eat方法,相当于d.eat("骨头"); System.out.println(re2); }
完整代码展示
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo2 {
@Test
public void getClassInfo() {
// 获取类信息
Class c1 = Student.class;
System.out.println(c1.getName());//类的全类名 demo2reflect.Student
System.out.println(c1.getSimpleName());//类名 Student
}
@Test
public void getConstructorInfo() throws Exception {
//获取类的构造器对象并对进行操作
//1.反射的第一步:获取Class对象,代表拿到类
Class c1 = Dog.class;
//2.获取构造器对象
Constructor[] cons = c1.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
}
//3.获取单个构造器
Constructor con = c1.getDeclaredConstructor();
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
Constructor con2 = c1.getDeclaredConstructor(String.class, int.class);
System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");
//4.创建对象
//暴力反射:暴力反射,可以访问私有的属性,方法,构造器
con.setAccessible(true);//暴力反射
Dog d1 = (Dog) con.newInstance();
System.out.println(d1);//输出:Dog{name='null', age=0, hobby='null'}
Dog d2 = (Dog) con2.newInstance("小黑", 2);
System.out.println(d2);//输出:Dog{name='小黑', age=2, hobby='null'}
}
@Test
public void getFieldInfo() throws Exception {
//目标:获取类的成员变量信息
//1.获取Class对象
Class c1 = Dog.class;
//2.获取成员变量对象
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "(" + field.getType().getName() + ")");
}
//3.获取单个成员变量对象
Field field = c1.getDeclaredField("hobby");
System.out.println(field.getName() + "(" + field.getType().getName() + ")");
Field field2 = c1.getDeclaredField("age");
System.out.println(field2.getName() + "(" + field2.getType().getName() + ")");
//4.获取成员变量的目的依然是取值和赋值
Dog d = new Dog("泰迪", 2);
field.setAccessible(true);
field.set(d, "睡觉");
System.out.println(d);//输出:Dog{name='泰迪', age=2, hobby='睡觉'}
String hobby = (String) field.get(d);
System.out.println(hobby);//输出:睡觉
}
@Test
public void getMethodInfo() throws Exception {
//目标:获取类的成员方法信息
//1.获取Class对象
Class c1 = Dog.class;
//2.获取成员方法对象
Method[] methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + "(" + method.getParameterCount() + ")");
}
//3.获取单个成员方法对象
Method m1 = c1.getDeclaredMethod("eat");//获取的是无参数的eat方法
Method m2 = c1.getDeclaredMethod("eat", String.class);//获取的是有参数的eat方法
System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")");
System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");
Dog d = new Dog("泰迪", 4);
m1.setAccessible(true);
Object re1 = m1.invoke(d);//唤醒对象的eat方法,相当于d.eat();
System.out.println(re1);//
Object re2 = m2.invoke(d, "骨头");//唤醒对象的eat方法,相当于d.eat("骨头");
System.out.println(re2);
}
}
反射的作用和应用场景
-
可以在运行时得到一个类的全部成分然后操作
-
可以破坏封装性
-
也可以破坏泛型的约束
-
更重要的用途是适合:做Java高级框架
-
基本上主流框架都会基于反射设计一些通用技术功能