反射的概念
反射(Reflection)是Java中一种强大的能力,它允许程序在运行时逻辑地检查类的能力和属性。
反射的主要功能包括:
1. 在运行时判断任意一个对象所属的类;
2. 在运行时构造任意一个类的对象;
3. 在运行时判断任意一个类所具有的成员变量和方法;
4. 在运行时调用任意一个对象的方法;
5. 生成动态代理。
反射的基本API包括:
1. Class类:代表一个类
2. Field类:代表类的成员变量
3. Method类:代表类的方法
4. Constructor类:代表类的构造方法
获取类的三种方式
- 1、通过已知的类型,获取class
public class GetClass {
public static void main(String[] args) {
Class<Apple> appleClass = Apple.getAppleClass();
System.out.println("appleClass = " + appleClass);
}
}
class Apple {
private String color;
public static Class<Apple> getAppleClass() {
Class<Apple> appleClass = Apple.class;
return appleClass;
}
}
- 2、通过实例化对象获取class
public class Class01 {
public static void main(String[] args) throws ClassNotFoundException {
//Class类对象不是new出来的,而是系统生成的
Dog dog = new Dog();
Class<? extends Dog> aClass = dog.getClass();
}
}
- 3、通过class.forName()获取
public class Class02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String classPath = "com.jorry.reflection.domain.Car";
Class<?> aClass = Class.forName(classPath);
//输出Class
System.out.println(aClass.getClass());
//得到包名
System.out.println(aClass.getPackage().getName());
//得到类名
System.out.println(aClass.getName());
//创建对象实例
Car o = (Car) aClass.newInstance();
//通过反射获取所有的属性
Field[] fields = aClass.getFields();
List<Field> list = Arrays.asList(fields);
list.forEach(field -> field.setAccessible(true));
Field fieldName = aClass.getField("name");
System.out.println("fieldName = " + fieldName);
//通过反射给属性设置值
fieldName.set(o, "zhangsan");
System.out.println(fieldName.get(o));
}
}
Java反射相关API
- Class常用操作
//获取所有的构造方法 / private public
public Constructor<?>[] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取类的父类
public native Class<? super T> getSuperclass()
//获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)
//获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()
//获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException
//根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类型的定义的所有属性
public Field[] getFields() throws SecurityException
// 根据属性命名获得特定的Field
public Field getField(String name)
- Method常用的操作方法
//获取所有的构造方法 / private public
public Constructor<?>[] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取类的父类
public native Class<? super T> getSuperclass()
//获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)
//获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()
//获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException
//根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类型的定义的所有属性
public Field[] getFields() throws SecurityException
// 根据属性命名获得特定的Field
public Field getField(String name)
- Field常用的操作方法
//属性与obj相等则返回true
public boolean equals(Object obj)
//获得obj中对应的属性值
public Object get(Object obj)
//设置obj中对应属性值
public void set(Object obj, Object value)
- Constructor
//根据传递的参数创建类的对象:initargs 构造方法参数
public T newInstance(Object... initargs)
##创建对象实例
public class User {
private Integer value;
public User() {
}
public User(int value) {
this.value = value;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
/**
* 1、根据class创建实例
*/
Class<User> userClass = User.class;
User user = userClass.newInstance();
/**
* 2、根据构造函数创建对象实例
*/
Constructor<User> constructor = User.class.getDeclaredConstructor();
constructor.newInstance();
/**
* 3、根据指定的参数类型的构造函数,实例化对象
*/
Constructor<User> cst = User.class.getDeclaredConstructor(Integer.class);
cst.newInstance();
}
}
反射执行方法
public class User {
private Integer value;
public User() {
}
public User(int value) {
this.value = value;
}
public void eat(String name) {
System.out.println("人吃饭,name:" + "\t" + name);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
/**
* 1、根据class创建实例
*/
Class<User> userClass = User.class;
User user = userClass.newInstance();
Method method = userClass.getDeclaredMethod("eat", String.class);
method.invoke(user, "Jorry");
}
}
反射获取Field,并对Field进行操作
public class User {
private Integer value;
public User() {
}
public User(int value) {
this.value = value;
}
public void eat(String name) {
System.out.println("人吃饭,name:" + "\t" + name);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
/**
* 1、根据class创建实例
*/
Class<User> userClass = User.class;
User user = userClass.newInstance();
//获取所有的属性,getField只能获取public的属性
Field[] fields = userClass.getFields();
Field field = userClass.getField("value");
Field[] fields = userClass.getDeclaredFields();
//获取特点字段的值
Field field = userClass.getDeclaredField("value");
//使用反射机制可以打破封装性,导致了java对象的属性不安全
field.setAccessible(true);
field.set(user,1007);
System.out.println("value = " + user.value);
}
}
- 反射的使用场景
1. 框架设计:反射被广泛用在框架的设计中,如Spring、Hibernate等,利用反射提供了更加灵活和松耦合的框架结构。
2. 调试和测试工具:IDE、代码分析工具等需要通过反射来了解代码的能力和属性,如Eclipse、IDEA都使用了反射。
3. 扩展性实现:通过反射来实例化对象和调用方法,可以实现动态加载类、根据配置来组装类的功能,提高代码的扩展性。
4. 安全框架:安全框架需要通过反射来检查类、方法的访问权限。如Java自身的SecurityManager。
5. 高级编程:通过反射实现依赖注入、动态代理等高级功能,提高编程灵活性。
6. 访问私有成员:反射可以通过setAccessible()方法访问私有成员,用于测试、调试等场景。
7. 性能优化:通过动态生成代码和JIT编译,使用反射提高某些场景下的性能。
8. 其它元编程:反射是元编程的重要方式,用于各种代码分析、生成等场景。
小彩蛋
高效的Hutool 当我用了一次Hutool中的反射工具类,真香,所以在此安利给大家:
- 1、导入Pom
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.21</version>
</dependency>
- 相关Api
public class ReflectionUtil {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
//1、获取所有属性
Field[] fields = ReflectUtil.getFields(Person.class);
Arrays.asList(fields).forEach(field -> field.setAccessible(true));
Person person = new Person();
//设置属性值
ReflectUtil.setFieldValue(person, "name", "jorry");
ReflectUtil.setFieldValue(person, "age", 18);
//获取属性字段值
String name = (String) ReflectUtil.getFieldValue(person, "name");
Integer age = (Integer) ReflectUtil.getFieldValue(person, "age");
//实例化对象
Person personInstance= ReflectUtil.newInstance(Person.class, "zhangsan", 18);
System.out.println("personInstance = " + personInstance);
//执行方法
ReflectUtil.invoke(person, "eat");
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("我要吃饭");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}