Java反射详解

反射,在解耦业务的框架中有广泛应用。另外还有注解,注解处理器以及泛型。他们组成了解耦框架们的四驾马车。

 

getConstructors和getDeclaredConstructors区别

getConstructors获取自身的public的构造方法。

getDeclaredConstructors获取自身的所有构造方法,无论是public, protect还是private, default.

两个方法都自能获取自身的构造方法,不能获取继承的构造方法。

 

getMethods和getDeclaredMethods区别

getMethods获取外部可访问的方法,也就是说不仅返回自身的public方法,还包含继承的public方法。

getDeclaredMethods获取所有自身的方法,无论是public, protect还是private, default.只能返回自身的方法。无法获取继承的任何方法。

        Test testRe = new TestRe();
        Class temp = testRe.getClass();
        String className = temp.getName();

        try {
            Constructor[] constructors = temp.getDeclaredConstructors();
            for (int i = 0; i < constructors.length; i++) {
//获取方法的修饰符,也就是public,protecth还是privated的
                int mod = constructors[i].getModifiers();
//把修饰符转成string
                System.out.println(Modifier.toString(mod) + " " + className+"(");
//获取方法的参数数组。
                Class[] parameterTypes = constructors[i].getParameterTypes();
                for (int j = 0; j < parameterTypes.length; j++) {
//打印参数名。
                    System.out.println(parameterTypes[j].getName());
                    if (parameterTypes.length > j + 1) {

                    }
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

getModifiers()

返回修饰符号。从命名就可以看出其实是个数组。通过&来判断有无。

不仅包括public, protect, private。

在Modifier类中的toString方法中,可以看到所有的修饰符:

public static String toString(int mod) {
    StringBuilder sb = new StringBuilder();
    int len;

    if ((mod & PUBLIC) != 0)        sb.append("public ");
    if ((mod & PROTECTED) != 0)     sb.append("protected ");
    if ((mod & PRIVATE) != 0)       sb.append("private ");

    /* Canonical order */
    if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
    if ((mod & STATIC) != 0)        sb.append("static ");
    if ((mod & FINAL) != 0)         sb.append("final ");
    if ((mod & TRANSIENT) != 0)     sb.append("transient ");
    if ((mod & VOLATILE) != 0)      sb.append("volatile ");
    if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
    if ((mod & NATIVE) != 0)        sb.append("native ");
    if ((mod & STRICT) != 0)        sb.append("strictfp ");
    if ((mod & INTERFACE) != 0)     sb.append("interface ");

    if ((len = sb.length()) > 0)    /* trim trailing space */
        return sb.toString().substring(0, len-1);
    return "";
}

getParameterTypes

返回方法中的参数列表。

getFields和getDeclareFields区别

getFields 获取指定的 public 字段 父类中的公有字段也能够获取到

getDeclareFields获取全部的 private、protected、default、public 的字段,, 但是只能取到该类自身定义的字段,从父类中继承的字段不能够获取到。

setAccessible

设置该字段是否可被访问, true表示可以访问该字段

 

反射的作用

根据class或者字符串生成实体对象, 再调用方法。以下是实际使用。

        Test testRe = new TestRe();
        Class temp = testRe.getClass(); 
       //也可以通过Class.forName()方法获取class实例
       //try {
       //     temp = Class.forName("com.com.nero.monalisa.activity.TestRe");
       // } catch (ClassNotFoundException e) {
            e.printStackTrace();
       // }
        String className = temp.getName();        

try {
            //获取无参构造方法
            Constructor constructor1 = temp.getConstructor();
            Class[] classes = new Class[]{int.class, String.class};
            //获取有参构造方法
            Constructor constructor2 = temp.getConstructor(classes);
            //实例化无参对象
            TestRe testRe1 = (TestRe) constructor1.newInstance();
            //实例化有参对象
            TestRe testRe2 = (TestRe) constructor2.newInstance(1, "alan");

            //调用public方法
            Method publicMethod = temp.getMethod("doPublicSomeThing", int.class, String.class);
            publicMethod.invoke(testRe2, 2, "gong");
            //调用private方法
            Method privateMethod = temp.getDeclaredMethod("doPrivateThing", int.class, String.class);
            //设置可以访问private方法
            privateMethod.setAccessible(true);
            privateMethod.invoke(testRe2, 3, "lindi");

            //调用private的静态方法
            Method privateStaticMethod = temp.getDeclaredMethod("work");
            privateStaticMethod.setAccessible(true);
            privateStaticMethod.invoke(null); //由于是静态的,所以不需要本对象传入。


            //获取私有字段,并且修改值
            Field field = temp.getDeclaredField("b");
            field.setAccessible(true);
            String value = (String) field.get(testRe2);
            field.set(testRe2, "alan gong");

            //获取静态私有字段,并且修改值。 这次修改是对全局有效的。
            Field privateStaticField = temp.getDeclaredField("c");
            privateStaticField.setAccessible(true);
            Object value1 =  privateStaticField.get(null);
            privateStaticField.set(value1, "lindi gong");
        } catch (Exception e) {
            e.printStackTrace();
        }

泛型与反射

关于Java泛型,很多人都有一个误解,认为Java代码在编译时会擦除泛型的类型,从而在运行时导致没法访问其类型,这其实并不完全正确,因为有一部分泛型信息是可以在运行时动态获取的,这部分信息基本能够满足我们日常开发中的大多数场景。

这部分信息都存在Class类,Method类里面可以用反射来获取部分泛型参数的类型信息。其实是非常有用的一个功能,比如在一些json工具的开源包里面,可以对Java里面泛型的各种List,List等类型做正确识别。

 

另外有必要知道以下两组的作用和区别:

getSuperclass和getGenericSuperclass区别

getSuperclass 返回直接继承的父类(由于编译擦除,没有显示泛型参数)

getGenericSuperclass 返回直接继承的父类(包含泛型参数)

//此段代码是在父类调用的。
Class clazz = this.getClass(); //this是子类对象。
Type type = clazz.getGenericSuperclass(); 
ParameterizedType param = (ParameterizedType)type;
           
Type[] types = param.getActualTypeArguments(); //由此得出泛型的具体类数组,如果有多余一个类型

getInterfaces和getGenericInterface区别

getInterfaces 返回直接实现的接口(由于编译擦除,没有显示泛型参数)

getGenericInterface 返回直接实现的接口(包含泛型参数)

 

反射还有一个特别的应用。替换系统单例对象的值。赋值成动态代理的对象。这样就可以起到拦截系统对象的目的了。

android插件化就是这么玩的。

 

最后有一个简化反射的封装库jOOR

mport static org.joor.Reflect.*;

String world = on("java.lang.String")  // Like Class.forName()
                .create("Hello World") // Call most specific matching constructor
                .call("substring", 6)  // Call most specific matching substring() method
                .call("toString")      // Call toString()
                .get();                // Get the wrapped object, in this case a String

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值