反射的定义
反射就是把java类中的各种成分映射成一个个的Java对象,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射机制简单理解为动态获取类中的信息。

反射常用的一些类
类 解释
Class 在反射中表示内存中的一个Java类,Class可以代表的实例类型包括,类和接口、
基本数据类型、数组
Object Java中所有类的超类
Constructor 封装了类的构造函数的属性信息,包括访问权限和动态调用信息
Field 提供类或接口的成员变量属性信息,包括访问权限和动态修改
Method 提供类或接口的方法属性信息,包括访问权限和动态调用信息
三种获取反射的形式
Class<?> Class.forName(String packageAndClassName);//使用完整的包名和类名调用反射对象
Class<?> 任意类对象.getClass(); //通过对象名的方式调用Class对象
Class<T> 类名.class; //通过类名调用Class对象
反射常用方法
Constructor[] getConstructors();//获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组
Constructor[] getDeclaredConstructors();//获取当前 Class 对应数据类型的所有构造方法对象数组,这里可以获取到私有方法
Constructor getConstructor(Class... parameterTypes);//根据指定的参数类型,个数,顺序获取到对应非私有化的Constructor对象
Constructor getDeclaredConstructor(Class... parameterTypes);//根据指定的参数类型,个数,顺序获取到对应非私有化的Constructor对象中
Object newInstance(Object... parameterValues); // 用于构造方法进行实例化操纵
Method[] getMethods();
Method[] getDeclaredMethods();
Method getMethod(String methodName, Class... parameterTypes);
Method getDeclaredMethod(String methodName, Class... parameterTypes);
Object invoke(Object obj, Object... parameterValues);
Field[] getFields();
Field[] getDeclaredFields();
Field getField(String fieldName);
Field getDeclaredField(String fieldName);
void set(Object obj, Object value);
Object get(Object obj);
void setAccessible(boolean flag);
public static void setAccessible(AccessibleObject[] array, boolean flag)
有很多小伙伴看到这里是不是头都都大了,有这么多方法,不急不急,其实都是一个套路,换汤不换药的东西 ,我们可以反射所用的方法分为四个类型,一Constructor 二Method 三Field 四setAccessible
下面开始一一解答
反射基本操作
我们先定义实体类(Person)有三个属性 id,age,name(私有),两个公开构造方法,一个私有构造方法,两个公开方法(test,game),两个私有方法(testPrivate)
public class Person {
private int id;
private int age;
private String name;
public int test = 10;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
}
private Person(int id) {
this.id = id;
}
public Person(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
private void testPrivate () {
System.out.println("类内私有化成员变量");
}
private void testPrivate(String name) {
System.out.println("玩"+name);
}
public void test() {
System.out.println("大吉大利,今晚吃鸡");
}
public void game(String name) {
System.out.println("玩" +name);
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
反射之一(构造方法--Constructor)
public class ConstructorObjectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 获取定制类型的Class对象
Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
//获取当前Class 对应数据类型的所有非私有化构造方法数组
Constructor<?>[] constructors = cls.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("-----------------");
//暴力反射 获取当前Class对应的数据类型的所有构造方法对象数组,包括私有化构造方法
Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println();
//根据用户指定的参数类型,顺序,个数获取对应的Constructor构造方法对象,并且非私有的
Constructor<?> c1 = cls.getConstructor(); //重点
Constructor<?> c2 = cls.getConstructor(int.class,int.class,String.class);
System.out.println(c2);
System.out.println(c1);
// 根据用户指定的参数类型,顺序,个数获取对应的Constructor构造方法对象,并且可以获取私有的方法
Constructor<?> c3 = cls.getDeclaredConstructor(int.class);
System.out.println(c3);
//通过构造方法实例化类对象
Person p1 = (Person) c1.newInstance();
Person p2 = (Person) c2.newInstance(1,23,"张三");
System.out.println(p1);
System.out.println(p2);
/*
new 构造方法形式局限性很大,通过反射方式操作,可以实现多种多样的类型要求
*/
Person person =new Person(2,21,"李四");
System.out.println(person);
//开启暴力反射的权限问题,直接调用会导致 IllegalAccessException 非法权限异常
c3.setAccessible(true);
Person p5 = (Person) c3.newInstance(12);
System.out.println(p5);
}
}
反射之二(Method)
public class MethodObjectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取指定类型的Class对象
Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
//可以获取Class对象对应类型的所有非私有化对象数组,包括父类继承给子类的成员方法
Method[] methods = cls.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
/*
暴力反射,可以获取Class对象对应类型的所有成员方法对象数组
,包含私有方法,但是不包含父类继承给子类的成员方法
*/
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println();
/*
根据指定的方法名称(methodName) 和 指定的方法参数类型,获取成员方法对象
*/
Method test = cls.getMethod("test");
System.out.println(test);
Method game = cls.getMethod("game", String.class);//重点
System.out.println(game);
System.out.println("----------");
/*
暴力反射,可以获取Class对象对应类型的所有成员方法对象数组
,包含私有方法,但是不包含父类继承给子类的成员方法,仅获取子类自有方法
*/
Method m1 = cls.getDeclaredMethod("testPrivate");
System.out.println(m1);
Method m2 = cls.getDeclaredMethod("testPrivate", String.class);
System.out.println(m2);
System.out.println();
//实例化对象
Object o = cls.getConstructor().newInstance();
//非私有化方法 o 表示当前实例化对象
test.invoke(o);
game.invoke(o, "PUBG");
System.out.println();
// m1.setAccessible(true);
// m2.setAccessible(true);
//同时给多个暴力反射的私有化方法给予权限
AccessibleObject.setAccessible(new AccessibleObject[]{m1,m2},true);
m1.invoke(o);
m2.invoke(o, "泥巴");
}
}
反射之三(Field)
public class FieldObjectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取指定类型的Class类型对象
Class<?> cls = Class.forName("com.itxiao.day09reflect.Person");
//获取类中所有非私有化成员变量对象数组
Field[] fields = cls.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println();
//根据指定的成员变量名称,获取对应的非私有化成员变量
Field test = cls.getField("test");
System.out.println(test);
System.out.println();
//【暴力反射】 根据指定的成员变量名称,获取对应的成员变量数组,包括私有化的成员变量
Field id = cls.getDeclaredField("id");
Field name = cls.getDeclaredField("name");
System.out.println(id);
System.out.println(name);
System.out.println("--------------");
// Field赋值和取值操作
//获取当前实例化对象
Object obj = cls.getConstructor().newInstance();
AccessibleObject.setAccessible(new AccessibleObject[]{id,name},true);
//给id赋值
id.set(obj, 20);
//给name赋值
name.set(obj, "狗哥");
System.out.println(obj);
System.out.println(id.get(obj));
System.out.println(name.get(obj));
}
}
反射的优缺点
优点:
提高了 Java 程序的灵活性和扩展性,降低耦合性,提高自适应能力。
允许程序创建和控制任何类的对象,无需提前硬编码目标类
应用很广,测试工具、框架都用到了反射
缺点:
性能问题:反射是一种解释操作,远慢于直接代码。因此反射机制主要用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用
模糊程序内部逻辑:反射绕过了源代码,无法再源代码中看到程序的逻辑,会带来维护问题
增大了复杂性:反射代码比同等功能的直接代码更复杂