zoukankan      html  css  js  c++  java
  • java Reflection(反射)基础知识讲解

    原文链接:小ben马java Reflection(反射)基础知识讲解

    1.获取Class对象的方式

    1.1)使用 "Class#forName"

    public static Class<?> forName(String className) throws ClassNotFoundException;
    

    如果没有获取到Class对象,则抛出异常 ClassNotFoundException;

    eg:

    Class<?> customerClazz = Class.forName("cn.xiaobenma.demo.core.reflection.VipCustomer");
    

    1.2)使用某个类的 ".class",eg:

    Class<?> customerClazz = VipCustomer.class;
    

    1.3)某个对象的 "#getClass()",eg:

    VipCustomer customer = new VipCustomer("001", "小ben马", "10086", VipCustomer.VIP_ADVANCED);
    Class<?> customerClazz = customer.getClass();
    

    2.判断是否为某个类的实例

    我们通常使用 "instanceof" 来判断对象是否为某个类的实例。同样,可以使用 "Class#isInstance()" 来判断

    public native boolean isInstance(Object obj);
    

    例子:

    boolean isCustomer = customer instanceof VipCustomer;
    
    isCustomer = VipCustomer.class.isInstance(customer);
    

    如果person为null, 上述例子都返回false。

    3. 创建实例

    3.1)使用 "Class#newInstance()": 要保证能访问类的无参构造方法

    public T newInstance() throws InstantiationException, IllegalAccessException;
    

    3.2)通过 "Constructor#newInstance(Object ... initargs)"

    public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    

    eg:

    Constructor<VipCustomer> constructor = getVipCustomerClass().getConstructor(String.class, String.class, String.class, int.class);
            VipCustomer customer = constructor.newInstance("001", "小ben马", "10086", VipCustomer.VIP_ADVANCED);
    

    4. 获取方法(类方法、成员方法)

    在Class中定义的方法如下:

    //a. 获取当前类及其父类,所有`public`类方法和成员方法
    public Method[] getMethods() throws SecurityException;
    
    //b. 通过方法名、参数类型,获取单个`public`类方法或者成员方法(当前类或父类定义的)
    public Method getMethod(String name, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException;
            
    //c. 获取当前类(不包括超类)定义的所有类方法和成员方法        
    public Method[] getDeclaredMethods() throws SecurityException;
    
    //d. 通过方法名、参数类型,获取单个当前类(不包括超类)定义的类方法或成员方法
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException;
            
    

    5. 获取构造方法

    在Class中定义的方法如下:

    //a. 获取当前类所有`public`构造方法
    public Constructor<?>[] getConstructors() throws SecurityException;
    
    //b. 根据参数类型,获取当前类单个`public`构造方法
    public Constructor<T> getConstructor(Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException;
    
    //c. 获取当前类所有构造方法
    public Constructor<?>[] getDeclaredConstructors() throws SecurityException;
    
    //d. 根据参数类型,获取当前类单个构造方法
    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException;
    
    

    6. 获取变量(类变量、成员变量)

    在Class中定义的方法如下:

    //a. 获取当前类及其超类,所有`public`类变量和成员变量
    public Field[] getFields() throws SecurityException;
    
    //b. 通过名称,获取当前类或超类,单个`public`类变量或者成员变量
    public Field getField(String name)
            throws NoSuchFieldException, SecurityException;
    
    //c. 获取当前类(不包括超类),所有类变量和成员变量
    public Field[] getDeclaredFields() throws SecurityException;
    
    //d. 通过名称,获取当前类(不包括超类),单个类变量或成员变量
    public Field getDeclaredField(String name)
            throws NoSuchFieldException, SecurityException;
    
    

    7. 通过inovke,调用对象的方法

    eg:

    Method setRank = getVipCustomerClass().getDeclaredMethod("setRank", int.class);
    setRank.invoke(customer, VipCustomer.VIP_NORMAL);
    

    8.获取和修改类变量或者成员变量的值

    8.1) Field#set(Object obj, Object value): 通过对象和变量值,设置变量,eg:

    Field field = getVipCustomerClass().getDeclaredField("rank");
    field.set(customer, VipCustomer.VIP_ADVANCED);
    

    8.2) Field#get(Object obj): 通过对象获取变量值,eg:

    Field field = getVipCustomerClass().getDeclaredField("rank");
    int rank = (int) field.get(customer);
    

    9.动态改变方法和变量的可访问性

    在使用反射获取被调用类的构造方法、方法或变量,可能对于调用类是不可访问的,如被调用类的"private"构造方法,"private" 方法, "private" 变量,会抛出 IllegalAccessException。
    java可以通过使用 "AccessibleObject#setAccessible(boolean flag)" 改变可访问性。
    "Constructor"、"Method" 和 "Field" 都是 "AccessibleObject" 的子类。

    eg:

    //在VipCustomer中定义类静态常量PRI_NO=100
    Field field = getVipCustomerClass().getDeclaredField("PRI_NO");
    field.setAccessible(true);
    Assert.assertEquals(100, field.get(null));
    
    //私有构造方法
    Constructor<VipCustomer> constructor = getVipCustomerClass().getDeclaredConstructor();
    constructor.setAccessible(true);
    VipCustomer customer = constructor.newInstance();
    Assert.assertNull(customer.getCustomerNo());
    Assert.assertNull(customer.getName());
    Assert.assertNull(customer.getMobilePhone());
    
    //调用私有类方法
    Method method = getVipCustomerClass().getDeclaredMethod("doNothingByVipCustomer");
    method.setAccessible(true);
    method.invoke(null);
    

    10.利用反射创建数组

    数组是比较特殊的类型。

    10.1) Array#newInstance(Class<?> componentType, int length),创建一维数组,eg:

    //一维数组
    Object array = Array.newInstance(String.class, 2);
    Array.set(array, 0, "小ben马");
    Array.set(array, 1, "xiaobenma");
    
    Assert.assertEquals("小ben马", Array.get(array, 0));
    Assert.assertEquals("xiaobenma", Array.get(array, 1));
    

    10.2) Array#newInstance(Class<?> componentType, int... dimensions),创建多维数组,eg:

    //多维数组
    //String[2][1]
    Object arrays = Array.newInstance(String.class, 2, 1);
    
    Object array0 = Array.newInstance(String.class, 1);
    Array.set(array0, 0, "小ben马");
    Array.set(arrays, 0, array0);
    
    Object array1 = Array.newInstance(String.class, 1);
    Array.set(array1, 0, "xiaobenma");
    Array.set(arrays, 1, array1);
    
    Assert.assertEquals("小ben马", Array.get(Array.get(arrays, 0), 0));
    Assert.assertEquals("xiaobenma", Array.get(Array.get(arrays, 1), 0));
    

    10.3)Array#get(Object array, int index)

    根据数组和相关索引获取对应的值

    10.4)Array#set(Object array, int index, Object value)

    根据索引和相关索引,设置对应的值

    11.Modifier说明

    通常在类中

    • 定义构造方法格式: [修饰符列表] 类名([参数列表])。
    • 定义变量的格式为: [修饰符列表] 返回类型 变量名称。
    • 定义方法的格式为: [修饰符列表] 返回类型 方法名([参数列表])。

    "Member#getModifiers()" 返回一个int类型,通过解释int的值,能获取定义的修饰符列表。"Constructor"、"Method" 和 "Field" 都是 "Member" 的实现类。

    修饰符返回的int值,需要通过 "Modifier" 解析。

    其中,

    • Modifier#toString(int mod): 打印定义的所有修饰符
    • Modifier#isXXX(int mod): 判断修饰符的类型

    如果你看过Modifier的源码,你会发现一个有趣的事情,修饰符是按bit位定义的,如:

     /**
     * The {@code int} value representing the {@code public}
     * modifier.
     */
    public static final int PUBLIC           = 0x00000001;
    
    /**
     * The {@code int} value representing the {@code private}
     * modifier.
     */
    public static final int PRIVATE          = 0x00000002;
    
    /**
     * The {@code int} value representing the {@code protected}
     * modifier.
     */
    public static final int PROTECTED        = 0x00000004;
    

    ps说明

    • 反射相关包java.lang.reflect
    • Proxy是反射中比较重要的应用,在后续博客单独更新。
    • 相关demo代码 core-java-learning
  • 相关阅读:
    团队项目第二阶段冲刺第六天
    团队项目冲刺第二阶段第五天
    团队项目冲刺第二阶段第四天
    团队项目冲刺第二阶段第三天
    大道至简阅读笔记1
    团队项目冲刺第二阶段第二天
    团队项目第二阶段冲刺第一天
    团队项目冲刺第九天
    团队项目冲刺第八天
    团队项目冲刺第七天
  • 原文地址:https://www.cnblogs.com/javaDeveloper/p/8550604.html
Copyright © 2011-2022 走看看