AI智能
改变未来

spring—反射(java.lang.reflect)


反射简介

反射是Java的高级特性之一,但是在实际的开发中,使用Java反射的案例却非常的少,但是反射确实在底层框架中被频繁的使用。

比如:JDBC中的加载数据库驱动程序,Spring框架中加载bean对象,以及态代理,这些都使用到反射,因为我们要想理解一些框架的底层原理,反射是我们必须要掌握的。

理解反射我们先从他的概念入手,那么什么是反射呢?

反射就是在运行状态能够动态的获取该类的属性和方法,并且能够任意的使用该类的属性和方法,这种动态获取类信息以及动态的调用对象的方法的功能就是反射。

实现上面操作的前提是能够获取到该类的字节码对象,也就是.class文件,在反射中获取class文件的方式有三种:

  1. 类名.class 如:Person.class
  2. 对象.class 如:person.class
  3. Class.forName(全类名)获取 如:Class.forName("ldc.org. demo.person")

这里有点区别的就是使用1,2(.class)方式获取Class对象,并不会初始化Class对象,而使用3(forName("全类名"))的方式会自动初始化Class对象。

反射

反射对应到Java中的类库就是在java.lang.reflect下,在该包下包含着FieldMethodConstructor类。

Field: 表示一个类的属性信息Method: 表示类的方法信息Constructor: 表示的是类的构造方法的信息

在反射中常用的方法,我这里做了一个列举,当然更加详细的可以查官方的API文档进行学习。

方法名 作用
getConstructors() 获取公共构造器
getDeclaredConstructors() 获取所有构造器
newInstance() 获取该类对象
getName() 获取类名包含包路径
getSimpleName() 获取类名不包含包路径
getFields() 获取类公共类型的所有属性
getDeclaredFields() 获取类的所有属性
getField(String name) 获取类公共类型的指定属性
getDeclaredField(String name) 获取类全部类型的指定属性
getMethods() 获取类公共类型的方法
getDeclaredMethods() 获取类的所有方法
getMethod(String name, Class[] parameterTypes) 获得类的特定公共类型方法
getDeclaredClasses() 获取内部类
getDeclaringClass() 获取外部类
getPackage() 获取所在包

User 类:

点击查看代码

package com.example.zhangchonghu.demo.controller.reflect;/*** @Description:* @author: 张重虎* @Date: 2022/2/17 11:20* @Version 1.0*/public class User {private String name;public Integer age;public User() {}public User(String name, Integer age) {this.name = name;this.age = age;}private void privateMethod() {System.err.println("私有方法执行了");}public void publicMethod(String param){System.err.println("公有方法执行了,参数为:"+param);}@Overridepublic String toString() {return "User{" +"name=\'" + name + \'\\\'\' +", age=" + age +\'}\';}}


在User的实体类中,有两个属性age和name,并且除了有两个测试方法privateMethod和publicMethod用于测试私有方法和公共方法的获取。接着执行如下代码:点击查看代码

package com.example.zhangchonghu.demo;import org.junit.jupiter.api.Test;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/*** @Description:* @author: 张重虎* @Date: 2022/2/17 11:54* @Copyright: Xi\'an Dian Tong Software Co., Ltd. All Rights Reserved.* @Version 1.0*/public class TestReflect {@Testpublic void test() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, ClassNotFoundException {//1、类名.class/*** Class clazz = User.class;*///2、对象.class/*** User user = new User();* Class clazz = user.getClass();*///3、Class.forName(全类名)获取Class clazz = Class.forName("com.example.zhangchonghu.demo.controller.reflect.User");Constructor constructor = clazz.getConstructor(String.class, Integer.class);//获取该类对象并设置属性的值Object obj = constructor.newInstance("张三", 18);//获得类全类名,既包含包路径String fullClassName = clazz.getName();//获得类名String className = clazz.getSimpleName();//获取类中公共类型(public)属性Field[] fields = clazz.getFields();String fieldName = "";for (Field field : fields) {//获取属性名fieldName = field.getName();System.out.println("public 属性名为:" + fieldName);}//获取类中所有的属性,包括 private 属性Field[] fieldsAll = clazz.getDeclaredFields();fieldName = "";for (Field field : fieldsAll) {fieldName = field.getName();System.out.println("private 属性名为:" + fieldName);}//获取指定公共属性值Field age = clazz.getField("age");Object value = age.get(obj);System.err.println("公共指定属性:" + value);//获得指定的私有属性值Field name = clazz.getDeclaredField("name");//设置为true才能获取私有属性name.setAccessible(true);Object value2 = name.get(obj);System.err.println("私有指定属性值:" + value2);//获取所有公共类型方法   这里包括 Object 类的一些方法Method[] methods = clazz.getMethods();String methodsName = "";for (Method method : methods) {methodsName = method.getName();System.out.println("公开的方法:" + methodsName);}//获取该类中的所有方法(包括private)Method[] methodsAll = clazz.getDeclaredMethods();methodsName = "";for (Method method : methodsAll) {methodsName = method.getName();System.out.println("私有的方法:" + methodsName);}//获取并使用指定方法Method privateMethod = clazz.getDeclaredMethod("privateMethod");//获取无参私有方法privateMethod.setAccessible(true);privateMethod.invoke(obj);//调用方法Method publicMethod = clazz.getMethod("publicMethod", String.class);//获取有参数方法publicMethod.invoke(obj, "张三");//调用有参方法}}


运行结果(多次运行结果顺序不相同,盲猜是和多线程有关。埋个雷,没有深入挖掘):

反射在jdk 1.5的时候允许对Class对象能够支持泛型,也称为泛化Class,具体的使用如下:

Class<User> user= User.class;//泛化class可以直接得到具体的对象,而不再是ObjectUseruser= user.newInstance();

泛化实现了在获取实例的时候直接就可以获取到具体的对象,因为在编译器的时候就会做类型检查。当然也可以使用通配符的方式,例如:Class<?>

反射优点和缺点

优点:反射可以动态的获取对象,调用对象的方法和属性,并不是写死的,比较灵活,比如你要实例化一个bean对象,你可能会使用new User()写死在代码中。

但是使用反射就可以使用class.forName(user).newInstance(),而变量名user可以写在xml配置文件中,这样就不用修改源代码,灵活、可配置。

缺点:反射的性能问题一直是被吐槽的地方,反射是一种解释操作,用于属性字段和方法的接入时要远远慢于直接使用代码,因此普通程序也很少使用反射。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » spring—反射(java.lang.reflect)