反射的使用范围
能使用反射是程序处于运行期,如果编译器是获取不到的
反射的作用
反射可以在没有实例的情况下去获得,如在框架中并不能直接获取实例对象,还能突破权限限制 如private
但是反射只能访问对象的实例 并修改数据 调用方法等等 但是不能修改别人的代码
反射:就是在运行的时候才知道要操作的类是什么,并且可以在运行的时候获取完整的类的结构,并调用对应的方法
通过反射 我们能获取到类中的哪些信息呢
1.获取类的信息
String name = "包名.类名";(如类名是Person)
Class clazz = (Class)Class.forName(name);
2.获取类的构造函数
1.获取类的所有构造函数
Constructor[] constructors = (Constructor[]) clazz.getConstructor();
1.2获取指定的构造函数
Constructor constructor = (Constructor) clazz.getConstructor(参数类型1.class,参数类型2.class,...)(注意 如果是int,double 等基本参数类型 应该用int.class double.class);
1.3.通过构造函数new出对象
Person obj = constructor.newInstance(参数值1,参数值2,...);(如Person obj = constructor.newInstance("姓名陈",24));
2.获取类中的方法
2.1获取clazz对应类中的所有方法,且获取从父类继承来的所有方法,但不包括private方法
Method[] methods = clazz.getMethods();
2.2获取clazz对应类的所有方法,但只获取当前类的所有方法,也包括private方法>
Method[] methods = clazz.getDeclaredMethods();
2.3获取指定的方法,需要参数名称和参数列表,无参数则不需要写
Method method = clazz.getDeclaredMethod("setName",String.class);(第一个是方法名,第二个是参数类型)
2.4执行具体的方法,第一个参数表示执行哪个对象的方法,剩余的参数是执行方法时需要传入的参数
Person person = clazz.newInstance();
method.invoke(person,18);(第一个参数是对象,第二个参数是方法的参数值);
私有方法必须在调用invoke之前加上一句method.setAccessible(true);
3.获取类中的成员变量 但是不能获取局部变量
这个参考后面的代码例子(代码例子写的非常完整)
4.获得类中注解相关的方法
- getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
- getAnnotations() 返回该类所有的公有注解对象
- getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
- getDeclaredAnnotations() 返回该类所有的注解对象
实例代码
//调用
ReflectDemo.testClass("com.xm.studyproject.reflect.Person");
ReflectDemo.testConstructor("com.xm.studyproject.reflect.Person");
ReflectDemo.testMethod(Person.class);
ReflectDemo.testField(Person.class);
--------------------------------------
//非常核心的代码 全是精华
package com.xm.studyproject.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 主要是针对反射的工具类。
* 反射使用的周期是在运行期 如果信息需要在编译期拿到是做不到的 可能需要注解处理器。
* 反射思想:就是在运行的时候才需要操作什么,获取类的完整结构 比如构造函数 变量 方法等并调用
* 什么时候需要使用反射呢?正常情况下我们可以new对象,但是有些框架的时候 我们没法直接使用
* 反射对性能是有一定影响的 但是没有我们想象的那么夸张
*/
public class ReflectDemo {
public static void testClass(String className) {
try {
//通过包名+类名的形式
Class<?> aClass = Class.forName(className);
//通过类实例化对象 如果没有非参的构造函数 需要传参 不然会报错
//Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数 如果该类没有默认的构造函数 直接这样调用会报错
//如果想通过调用带参的生成带参的实例 需要通过newInstance Constructor.newInstance() 可以根据传入的参数,调用任意构造函数。
//具体使用参考 https://blog.csdn.net/qq_41378597/article/details/102486128
//会报错 下面这种写法会报错
Person person = (Person) aClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
//通过包名+类名的形式
public static void testConstructor(String className) {
Class<?> aClass = null;
try {
aClass = Class.forName(className);
//获取当前类中的所有构造函数 包括private
// private的范围是在当前类中
// 默认修饰符的范围是当前包中的所有地方
//protected的范围是当前包中所有地方 以及当前类的子类中
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println(constructor);
}
//获取当前类及父类的所有构造方法 但是不包括private
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//获取当前类(不包含父类)指定的构造函数 传入构造函数相应参数 但是如参数本身就是int 也是传入int而不是Integer
//这种方式是获取不到私有的构造函数
Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
//实例化构造函数 传入参数的真实值
Person newInstance = (Person) constructor.newInstance("小米", 28);
System.out.println(newInstance);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//换种方式传入
public static void testMethod(Class aClass) {
//获取当前类中的所有方法 包括private方法
Method[] declaredMethods = aClass.getDeclaredMethods();
//获取当前类以及父类的所有方法 但是不包括private
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取当前类(不包含父类)中指定的方法
//第一个参数是方法名 也就是调用哪个方法 第二个参数就是方法中传入的参数
Method method = null;
try {
//这种方式是获取不到私有方法的
//method = aClass.getMethod("setInfo", String.class, int.class);
//需要是这种方式
method = aClass.getDeclaredMethod("setInfo", String.class, int.class);
//调用方法前 如果是私有方法 需要设置可访问权限为true 不然会报错
method.setAccessible(true);
//调用方法
//第一个参数是对象 也就是实例 因为没有实例就不存在调用方法一说
//第二个就是参数赋值 也就是实际的值
Constructor constructor = aClass.getDeclaredConstructor(String.class);
Object o = constructor.newInstance("小小");
System.out.println(method);
Object invoke = method.invoke(o, "小花", 30);
System.out.println(invoke);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static void testField(Class aClass) {
//获取当前类的成员变量 不包括局部变量
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
//获取当前类及父类的成员变量 但是不包括private Object成员变量都是私有的
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
//获取指定变量
//参数就是变量名
Field field = null;
try {
//获取实例
Constructor constructor = aClass.getDeclaredConstructor(String.class);
Object object = constructor.newInstance("小小");
//获取私有成员变量 如果没有获取到是会报错的
//field = aClass.getField("name");
//获取实例对象中变量的值
field = aClass.getDeclaredField("name");
//需要上面getDeclaredField可以获取到私有成员变量 但是如果想获取私有变量的值还是需要
field.setAccessible(true);
String name = (String) field.get(object);
System.out.println(name);
//对实例中的变量进行赋值 如果该变量是私有的需要设置
field.setAccessible(true);
field.set(object, "小陈同学");
System.out.println(field.get(object));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
-----------------------------
//提供的实体bean
package com.xm.studyproject.reflect;
public class Person {
private String name;
private int age;
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void setInfo(String name, int age) {
int tempName = 3;
this.name = name;
this.age = age;
}
}