• Java-反射基础


    反射基础

    1. Class类

    通过对象获取Class类

    Object obj = new Object();
    Class cl = obj.getClass();
    
    • 1
    • 2

    通过类名获取Class类

    String className = "java.util.Random";//包的名字也作为类名一部分
    Class cl = Class.forName(className);
    
    • 1
    • 2

    通过T.class匹配

    Class cl1 = Random.class;
    Class cl2 = int.class;
    
    • 1
    • 2

    通过==运算符实现两个类对象比较

    if(e.getClass() == Random.class)...
    
    • 1

    通过newInstance()调用默认构造器

    Object m = cl.newInstance();//如果没有默认构造器,将会抛出异常
    
    • 1

    通过newInstance(Object[] args)调用构造器

    Object m = cl.newInstance(a,b,c);
    
    • 1

    2. 检查类的结构

    java.lang.reflect包中有三个类Field、Method和Constructor分别描述类的域、方法和构造器。

    在Class对象中,可以调用以下方法获取上述结构

    获取域

    Field[] getFields();//获取该类以及父类(如果有)的公开域
    Field[] getDeclaredFields();//获取该类所有域
    
    • 1
    • 2

    获取方法

    Method[] getMethods();//获取该类以及父类(如果有)的公开方法
    Method[] getDeclaredMethods();//获取该类所有方法
    
    • 1
    • 2

    获取构造器

    Constructor[] getConstructors();//获取公开构造器
    Constructor[] getDeclaredConstructors();//获取该类所有构造器
    
    • 1
    • 2

    3. Field、Method和Constructor的共有方法

    Class getDeclaringClass()

    返回Field.class,Method.class或Constructor.class,即返回描述类中定义的构造器,方法或域的Class对象.

    Class[] getExceptionTypes()

    仅在Constructor和Method类中,返回一个描述方法抛出的异常类型的Class数组

    int getModifiers()

    返回一个用于描述构造器,方法或域的修饰符的int值,使用Modifier类中的这个方法可以分析这个返回值。

    String getName()

    返回一个用于描述构造器,方法或域名的字符串

    Class[] getParameterTypes()

    仅在Constructor和Method类中,返回一个用于描述参数类型的Class对象数组

    Class getReturnedType()

    仅在Method类中,返回一个用于描述返回类型的Class对象。

    4. java.lang.reflect.Modifier

    static String toString(int modifiers);
    static boolean isAbstract(int modifiers);
    static boolean isFinal(int modifiers);
    ...
    
    • 1
    • 2
    • 3
    • 4

    这些方法可以用来检测方法名中对应的修饰符在modifier值中的情况。

    5. 获取、更改对象的域

    java.lang.reflect.AccessibleObject 设置访问检查权限

    void setAccessible(boolean flag)

    为反射对象设置可访问标志,true表示屏蔽Java语言的访问检查,即便是私有属性也可以被查询和设置。

    boolean isAccessible()

    返回反射对象的可访问标志的值

    static void setAccessible(AccessibleObject[] array, boolean flag)

    设置对象数组可访问标志的快捷方式

    java.lang.Class 获取指定的域

    Field getField(String name);
    Field[] getFields();//返回指定名称的公有域,或包含可检查的域的数组
    
    Field getDeclaredField(String name);
    Field[] getDeclaredFields();//获取类中声明的给定名称的域,或者包含声明的全部域的数组
    
    • 1
    • 2
    • 3
    • 4
    • 5

    java.lang.reflect.Field 获取检查或设置域的值

    Object get(Object obj);//返回obj对象中用Field对象表示的域的值
    void set(Object obj, Object newValue);//用一个新值设置Obj对象中Field对象表示的域
    
    • 1
    • 2

    例如现在有一个男孩,需要更改其名字

    Boy boy = new Boy("张三");
    Class cl = boy.getClass();
    Field f = cl.getDeclaredField("name");//注意用Declared
    f.setAccessible(true);//设置屏蔽Java的访问检查
    f.set(boy,"李四");//更改boy对象中与变量f(一个cl中叫做name的域)对应的值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6. 泛型数组

    理解一段代码,用于数组扩展

    public static Object goodCopyOf(Object a, int newLength){
        Class cl = a.getClass();
        if(!cl.isArray()) return null;
        Class componentType = cl.getComponentType();
        int length = Array.getLength(a);
        Object newArray = Array.newInstance(componentType,newLength);
        System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
        return newArray;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    传入的原数组a用的是Object类型,而不用Object[]类型,因为int[]不能转为Object[]类型。

    首先判断a是不是Array类型,其次再通过getComponentType获取数组元素类型,如果cl不是Array的类的话,将会返回null。

    之所以要通过元素类型来创建一个例如Employee[]的新数组,而不是直接创建一个Object[]的新数组,是因为Object[]无法直接转成Employee[],这会带来困扰。

    java.lang.reflect.Array

    static Object get(Object array,int index);
    static xxx getXxx(Object array,int index);//xxx为boolean,byte,char等,用于返回存储在给定位置上的给定数组的内容
    
    static void set(Object array,int index,Object newValue);
    static setXxx(Object array,int index, xxx newValue);//xxx为boolean,byte,char等,用于将一个新的值存储到给定位置上的给定数组中
    
    static int getLength(Object array);//返回数组长度
    
    static Object newInstance(Class componentType, int length);
    static Object newInstance(Class componentType, int[] lengths);
    //返回一个具有给定类型,给定维度的数组
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7. 调用任意方法 Method.invoke()

    Method类中有一个invoke方法,它允许调用包装在当前Method对象中的方法。invoke的方法签名是:

    Object invoke(Object obj, Object... args);
    
    • 1

    第一个是隐式参数,其余都是显式参数。(隐式参数:方法的调用者;显式参数:在方法参数列表中声明的参数)

    如果是静态方法,第一个参数obj设置为null。在使用包装器传递基本类型的值的时候,基本类型的返回值必须是未包装的。

    下面是示例:

    public class Boy{
        private String name;
        
        public String getName(){return name;}
        
        private void setName(String newName){this.name = newName;}
        private static void sayHello(){
            System.out.println("hello");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    首先通过反射设置新名字

    Boy boy = new Boy("张三");
    Class cl = boy.getClass();
    Method m1 = cl.getDeclaredMethod("setName",String.class);
    m1.setAccessible(true);//method也需要屏蔽Java的访问检查
    m1.invoke(boy,"李四");//调用者为boy对象,调用时需要的参数为新的名字"李四"
    
    Method m2 = cl.getDeclaredMethod("sayHello");
    m2.setAccessible(true);
    m2.invoke(null);//静态方法,隐式参数为null(调用者设置为null)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    JavaScript实现经典消方块游戏
    动态加载布局的技巧
    uni-app:实现图片周围的图片按照圆进行展示
    读《GaitPart: Temporal Part-based Model for Gait Recognition》
    2.5 整理了3种小红书笔记爆文写作文案【玩赚小红书】
    Web3D水厂:数字孪生智慧水务三维WebGL可视化管理系统
    MFC 常用控件
    实现抖音视频滑动功能vue3+swiper
    Leetcode64. 最小路径和
    【COSBench系列】1. COSBench认识、使用、结果分析
  • 原文地址:https://blog.csdn.net/weixin_43093006/article/details/128001665