3、反射

1、英文意思

* Declared:   声明的
* 构造器:      Constructors
* 属性:        Fields
* 修饰符:      Modifiers
* 返回类型:    ReturnType
* 方法名:      Name
* 参数列表:    ParameterTypes
* 注解:       Annotations
* 异常:       ExceptionTypes
* 调用:       invoke
* 接口:       Interfaces
* 父类:       Superclass
* 包:         Package

2、概念

反射是指对于任何一个 Class 类,在 "运行的时候" 都可以直接得到这个类全部成分

  • 在运行时,可以直接得到这个类的构造器对象:Constructor
  • 在运行时,可以直接得到这个类的成员变量对象:Field
  • 在运行时,可以直接得到这个类的成员方法对象:Method
  • 这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制

反射的关键:反射的第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分
反射可以破坏封装性,私有的也可以执行了

3、类对象

// 四种方式
Class c1 = Class.forName("全类名");

Class c2 = 类名.class;

Class c3 = 类的对象.getClass();

ClassLoader classLoader = 类名.class.getClassLoader();
Class c4 = classLoader.loadClass("全类名"); 
Class<?> c1 = Class.forName("d12.Student");

Class<Student> c2 = Student.class;

Student student = new Student();
Class<? extends Student> c3 = student.getClass();

ClassLoader classLoader = T1.class.getClassLoader();
Class<?> c4 = classLoader.loadClass("d12.Student");

System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);

4、API

4.1、构造器对象

方法 说明
Constructor<?>[] getConstructors() 返回所有构造器对象的数组(只能拿 public 的)
Constructor<?>[] getDeclaredConstructors() 返回所有构造器对象的数组,存在就能拿到
Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个构造器对象(只能拿 public 的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造器对象,存在就能拿到

构造器对象的方法 说明
public T newInstance(Object... initargs) 根据指定的构造器创建对象
public void setAccessible(boolean flag) 设置为 true,表示取消访问检查,进行暴力反射

4.2、变量对象

方法 说明
Field[] getFields() 返回所有成员变量对象的数组(只能拿 public 的)
Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
Field getField(String name) 返回单个成员变量对象(只能拿 public 的)
Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到

变量对象的方法 说明
void set(Object obj, Object value) 赋值 obj.set(value)
Object get(Object obj) 获取值 obj.get()
String getName() 获取当前属性的名称
Class<?> getType() 获取当前属性的类型
int getModifiers() 获取当前属性的访问修饰符
public void setAccessible(boolean flag) 设置为 true,表示取消访问检查,进行暴力反射

4.3、方法对象

方法 说明
Method[] getMethods() 返回所有成员方法对象的数组(只能拿 public 的)
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象(只能拿 public 的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象,存在就能拿到

方法对象的方法 说明
Object invoke(Object obj, Object... args) 运行方法
参数一:用 obj 对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
getModifiers() 获取当前方法的访问修饰符
getReturnType() 获取当前方法的返回类型
getName() 获取当前方法的名称
getParameterTypes() 获取当前方法的参数列表
getExceptionTypes() 获取当前方法的异常
getAnnotations() 获取当前方法的注解
public void setAccessible(boolean flag) 设置为 true,表示取消访问检查,进行暴力反射

4.4、其他

方法 描述
getPackage() 获取当前类所在的包
getSimpleName() 获取当前类的类名
getName() 获取当前类的全路径名(包名 + 类名)
getInterfaces() 获取当前类实现的接口(不包括父类)
getAnnotations() 获取修饰当前类的注解
getSuperclass() 获取当前类的父类的字节码信息

5、绕过编译阶段为集合添加数据

反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了
ArrayList<String> 和 ArrayList<Integer> 的类型都是 ArrayList

ArrayList<String> list = new ArrayList<>();
list.add("你好");

// 方式一
Class<? extends ArrayList> c = list.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
add.invoke(list, true);
System.out.println(list);

// 方式二
ArrayList newList = list;
newList.add(17.2);
System.out.println(list);

6、通用框架的底层原理

反射的作用

  • 可以在运行时得到一个类的全部成分,然后操作
  • 可以破坏封装性(很突出)
  • 可以破坏泛型的约束性(很突出)
  • 更重要的用途是适合:做 Java 高级框架
  • 基本上主流框架都会基于反射设计一些通用技术功能

需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去

  • 定义一个方法,可以接收任意类的对象
    每次收到一个对象后,需要解析这个对象的全部成员变量名称
    这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
  • 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息
    遍历成员变量信息,然后提取本成员变量在对象中的具体值
    存入成员变量名称和值到文件中去即可
public class Test {
    public static void main(String[] args) throws Exception {
        Student student = new Student(10, "张三");
        System.out.println(test(student));
        // 结果: Student{age:10,name:张三}
    }

    public static String test(Object obj) throws IllegalAccessException {
        Class<?> c = obj.getClass();
        Field[] fields = c.getDeclaredFields();

        StringBuilder sb = new StringBuilder();
        sb.append(c.getSimpleName()).append("{");

        for (Field field : fields) {
            field.setAccessible(true);
            sb
                .append(field.getName())
                .append(":")
                .append(field.get(obj))
                .append(",");
        }
        sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");

        sb.append("}");
        return sb.toString();
    }
}
posted @ 2023-06-11 00:04  lidongdongdong~  阅读(21)  评论(0编辑  收藏  举报