zoukankan      html  css  js  c++  java
  • Java反射

    反射

    反射简介

    java的反射就是通过Class来在运行时获取类的完整结构信息 & 调用对象的方法。正常情况下,Java类在编译前,就已经被加载到JVM中;而反射机制使得程序运行时还可以动态地去操作类的变量、方法等信息。

    反射的本质是当一个类被加载以后,Java虚拟机就会自动产生一个 Class对象。通过这个 Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。

    优点是灵活在运行时才动态创建&获取,缺点则是效率低,容易破坏类结构(因为绕过了源码容易干扰类原有内部逻辑)。

    效率低主要是由以下几个方面造成:

    • 反射调用过程中会产生大量的临时对象,这些对象会占用内存,可能会导致频繁 gc,从而影响性能。
    • 反射调用方法时会从方法数组中遍历查找,并且会检查可见性等操作会耗时。
    • 反射调用时编译器难以对动态调用的代码提前做优化。
    • 反射一般会涉及自动装箱/拆箱和类型转换,都会带来一定的资源开销

    反射使用

    大致分为以下几个方面:

    • 获取Constructor类对象
     <-- 1. 获取类的构造函数(传入构造函数的参数类型)->>
       // a. 获取指定的构造函数 (公共 / 继承)
       Constructor<T> getConstructor(Class<?>... parameterTypes)
       // b. 获取所有的构造函数(公共 / 继承) 
       Constructor<?>[] getConstructors(); 
       // c. 获取指定的构造函数 ( 不包括继承)
       Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
       // d. 获取所有的构造函数( 不包括继承)
       Constructor<?>[] getDeclaredConstructors(); 
     // 最终都是获得一个Constructor类对象
     
     // 特别注意:
       // 1. 不带 "Declared"的方法支持取出包括继承、公有(Public) & 不包括有(Private)的构造函数
       // 2. 带 "Declared"的方法是支持取出包括公共(Public)、保护(Protected)、默认(包)访问和私有(Private)的构造方法,但不包括继承的构造函数
       // 下面同理
    
    • 获取Method类对象
    <--  2. 获取类的属性(传入属性名) -->
      // a. 获取指定的属性(公共 / 继承)
       Field getField(String name) ;
      // b. 获取所有的属性(公共 / 继承)
       Field[] getFields() ;
      // c. 获取指定的所有属性 (不包括继承)
       Field getDeclaredField(String name) ;
      // d. 获取所有的所有属性 (不包括继承)
       Field[] getDeclaredFields() ;
    // 最终都是获得一个Field类对象
    
    • 获取Field类对象
    <-- 3. 获取类的方法(传入方法名 & 参数类型)-->
      // a. 获取指定的方法(公共 / 继承)
        Method getMethod(String name, Class<?>... parameterTypes) ;
      // b. 获取所有的方法(公共 / 继承)
       Method[] getMethods() ;
      // c. 获取指定的方法 ( 不包括继承)
       Method getDeclaredMethod(String name, Class<?>... parameterTypes) ;
      // d. 获取所有的方法( 不包括继承)
       Method[] getDeclaredMethods() ;
    // 最终都是获得一个Method类对象
    
    • 其他常用方法
    getSuperclass(); 
    // 返回父类
    
    String getName(); 
    // 作用:返回完整的类名(含包名,如java.lang.String ) 
     
    Object newInstance(); 
    

    总结来说分为带 "Declared"和不带 "Declared",不带Declared的方法只能获取公有属性以及从父类继承的,带Declared的则只能访问自己定义的属性(但是可以获取私有属性)。还有可以根据是否提供参数分类,带参数的方法一般是根据参数匹配符合的属性,不带参数的获取方法会返回所有符合的属性。

    当获取到Constructor、Method、Field之后我们可以根据获取的对象做进一步的获取信息或操作

    <-- 1. 通过Constructor 类对象获取类构造函数信息 -->
      String getName();// 获取构造器名
      Class getDeclaringClass();// 获取一个用于描述类中定义的构造器的Class对象
      int getModifiers();// 返回整型数值,用不同的位开关描述访问修饰符的使用状况
      Class[] getExceptionTypes();// 获取描述方法抛出的异常类型的Class对象数组
      Class[] getParameterTypes();// 获取一个用于描述参数类型的Class对象数组
    
    <-- 2. 通过Field类对象获取类属性信息 -->
      String getName();// 返回属性的名称
      Class getDeclaringClass(); // 获取属性类型的Class类型对象
      Class getType();// 获取属性类型的Class类型对象
      int getModifiers(); // 返回整型数值,用不同的位开关描述访问修饰符的使用状况
      Object get(Object obj) ;// 返回指定对象上 此属性的值
      void set(Object obj, Object value) // 设置 指定对象上此属性的值为value
     
    <-- 3. 通过Method 类对象获取类方法信息 -->
      String getName();// 获取方法名
      Class getDeclaringClass();// 获取方法的Class对象 
      int getModifiers();// 返回整型数值,用不同的位开关描述访问修饰符的使用状况
      Class[] getExceptionTypes();// 获取用于描述方法抛出的异常类型的Class对象数组
      Class[] getParameterTypes();// 获取一个用于描述参数类型的Class对象数组
    
    <--额外:java.lang.reflect.Modifier类 -->
    // 作用:获取访问修饰符
    
    static String toString(int modifiers)   
    // 获取对应modifiers位设置的修饰符的字符串表示
    
    static boolean isXXX(int modifiers) 
    // 检测方法名中对应的修饰符在modifiers中的值
    

    数组与枚举的反射

    //创建元素类型、元素长度指定的数组
    public static Object newInstance(Class<?> componentType, int length)
    //创建多维度的数组,dimensions可连续传递多个,分别代表不同维度
    public static Object newInstance(Class<?> componentType, int... dimensions)
    //获取指定数组的对应索引的值
    public static native Object get(Object array, int index)
    //赋值给指定数组的对应索引下的值
    public static native void set(Object array, int index, Object value)
    //获取数组长度
    public static native int getLength(Object array)
    
    
    //获取当前枚举类型Class的所有定义的枚举常量
    public T[] getEnumConstants()
    
    String[] strArr = new String[10];
    int[][] twoDimArr = new int[3][2];
    int[] oneDimArr = new int[10];
    Class<? extends String[]> strArrCls = strArr.getClass();
    Class<? extends int[][]> twoDimArrCls = twoDimArr.getClass();
    Class<? extends int[]> oneDimArrCls = oneDimArr.getClass();
    

    获取基本数据类型的Class

    //基本类型的class即为对应的包装类型
    Class<Integer> intCls = int.class;
    Class<Byte> byteCls = byte.class;
    Class<Character> charCls = char.class;
    Class<Double> doubleCls = double.class;
    //void也是一种特殊的类型,返回的也是对应的包装类Void
    Class<Void> voidCls = void.class;
    

    反射应用

    反射是Android源码里面应用最多的地方,小到xml的解析,大到dex文件的加载,application的启动,均大量运用了反射。

    • 反射生成对象、执行方法、获取类信息
    • 工厂模式优化
    • 动态代理

    Java 反射真的很慢吗?

    详解Java反射操作

    反射技术在Android中的应用

    Java反射:这是一份全面 & 详细的 Java反射机制 学习指南

    一篇文章带你学懂Java反射

    大家都说 Java 反射效率低,你知道原因在哪里么

  • 相关阅读:
    数据库字段说明查询
    MUI 微信支付代码
    数据库 批量删除表
    c# 微信开发 《内容回复或事件触发》
    C# 微信开发 《验证签名》
    SQL SERVER占用CPU过高排查和优化
    类属性验证简单说明
    地图纠偏
    区块链-6一个故事告诉你比特币的原理及运作机制
    区块链-5区块链技术入门,涉及哪些编程语言?
  • 原文地址:https://www.cnblogs.com/Robin132929/p/13721131.html
Copyright © 2011-2022 走看看