阅读 563

反射技术实用详解

image.png

我能抽象出整个世界...
但是我却不能抽象出你... 
你肯定是一个单例,因为你是那样的独一无二... 
所以我的世界并不完整... 
我可以重载甚至覆盖这个世界里的任何一种方法... 
但是却不能覆盖对你的思念...
也许命中注定了,你与我存在于不同的包里... 
在你的世界里,你被烙上了私有的属性... 
我用尽全身力气,也找不到访问你的接口... 
# 我不愿就此甘心,找到了藏身神殿的巫师,教会了我穿越时空的方法...
# 终于,我用反射这把利剑,打开了你空间的缺口...
# 并发现了接近你的秘密...
当我迫不及待地调用了爱你这个方法... 
并义无返顾的把自己作为参数传进这个方法时...
我才发现爱上你是一个没有终止条件的递归... 
它不停的返回我对你的思念并压入我心里的堆栈...
在这无尽的黑夜中 ,终于体验到你对我爱的回调... 
我的内存里已经再也装不下别人... 
当我以为将与你在这个死循环中天荒地老时... 
万恶的系统抛出了爱的异常... 
此刻我才发现,我不过是操纵于虚拟机下的一个线程,你也是... 
但我毫不后悔,因为在爱的洗礼之后... 
我看见了一个新的生命,那是我们的, 继承 ...
我们的继承越来越多,他们的风格都是多态的...
这使得我们在别人面前可以风光无限
复制代码

今天在地铁上看见了这段话,其中有几句话(#部分),令我无比动容,对于我们敲代码的人来说,代码无疑是我的爱人,是我的知己,然而,对于爱人知己的私密部分我们总是喜欢窥视,因为爱一个必须了解一个人。哈哈,所以,反射这把利剑就是我们通往隐秘部分的阶梯、是通道、是表达爱的方式。好了,地铁上也不好码字,正式介绍反射。

一、反射

Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。(来源网络)

1.1 反射作用

反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗(来源网络)

先上一个在开发中常用的反射工具类,细节部分1.2介绍,看不看无所谓哈

object RefInvoke {
    //无参
    fun createObject(className: String?): Any? {
        val pareTyples = arrayOf<Class<*>>()
        val pareVaules = arrayOf<Any>()
        try {
            val r = Class.forName(className)
            return createObject(r, pareTyples, pareVaules)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
        return null
    }

    //无参
    fun createObject(clazz: Class<*>): Any? {
        val pareTyple = arrayOf<Class<*>>()
        val pareVaules = arrayOf<Any>()
        return createObject(clazz, pareTyple, pareVaules)
    }

    //一个参数
    fun createObject(className: String?, pareTyple: Class<*>, pareVaule: Any): Any? {
        val pareTyples = arrayOf(pareTyple)
        val pareVaules = arrayOf(pareVaule)
        try {
            val r = Class.forName(className)
            return createObject(r, pareTyples, pareVaules)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
        return null
    }

    //一个参数
    fun createObject(clazz: Class<*>, pareTyple: Class<*>, pareVaule: Any): Any? {
        val pareTyples = arrayOf(pareTyple)
        val pareVaules = arrayOf(pareVaule)
        return createObject(clazz, pareTyples, pareVaules)
    }

    //多个参数
    fun createObject(
        className: String?,
        pareTyples: Array<Class<*>>,
        pareVaules: Array<Any>?
    ): Any? {
        try {
            val r = Class.forName(className)
            return createObject(r, pareTyples, pareVaules)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
        return null
    }

    //多个参数
    fun createObject(clazz: Class<*>, pareTyples: Array<Class<*>>, pareVaules: Array<Any>?): Any? {
        try {
            val ctor = clazz.getDeclaredConstructor(*pareTyples)
            ctor.isAccessible = true
            return ctor.newInstance(pareVaules)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }


    //多个参数
    fun invokeInstanceMethod(
        obj: Any?,
        methodName: String?,
        pareTyples: Array<Class<*>>,
        pareVaules: Array<Any>?
    ): Any? {
        if (obj == null) return null
        try {
            //调用一个private方法
            val method: Method =
                obj.javaClass.getDeclaredMethod(methodName, *pareTyples) //在指定类中获取指定的方法
            method.setAccessible(true)
            return method.invoke(obj, pareVaules)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    //一个参数
    fun invokeInstanceMethod(
        obj: Any?,
        methodName: String?,
        pareTyple: Class<*>,
        pareVaule: Any
    ): Any? {
        val pareTyples = arrayOf(pareTyple)
        val pareVaules = arrayOf(pareVaule)
        return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules)
    }

    //无参
    fun invokeInstanceMethod(obj: Any?, methodName: String?): Any? {
        val pareTyples = arrayOf<Class<*>>()
        val pareVaules = arrayOf<Any>()
        return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules)
    }


    //无参
    fun invokeStaticMethod(className: String?, method_name: String?): Any? {
        val pareTyples = arrayOf<Class<*>>()
        val pareVaules = arrayOf<Any>()
        return invokeStaticMethod(className, method_name, pareTyples, pareVaules)
    }

    //一个参数
    fun invokeStaticMethod(
        className: String?,
        method_name: String?,
        pareTyple: Class<*>,
        pareVaule: Any
    ): Any? {
        val pareTyples = arrayOf(pareTyple)
        val pareVaules = arrayOf(pareVaule)
        return invokeStaticMethod(className, method_name, pareTyples, pareVaules)
    }

    //多个参数
    fun invokeStaticMethod(
        className: String?,
        method_name: String?,
        pareTyples: Array<Class<*>>,
        pareVaules: Array<Any>?
    ): Any? {
        try {
            val obj_class = Class.forName(className)
            return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    //无参
    fun invokeStaticMethod(clazz: Class<*>, method_name: String?): Any? {
        val pareTyples = arrayOf<Class<*>>()
        val pareVaules = arrayOf<Any>()
        return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules)
    }

    //一个参数
    fun invokeStaticMethod(
        clazz: Class<*>,
        method_name: String?,
        classType: Class<*>,
        pareVaule: Any
    ): Any? {
        val classTypes = arrayOf(classType)
        val pareVaules = arrayOf(pareVaule)
        return invokeStaticMethod(clazz, method_name, classTypes, pareVaules)
    }

    //多个参数
    fun invokeStaticMethod(
        clazz: Class<*>,
        method_name: String?,
        pareTyples: Array<Class<*>>,
        pareVaules: Array<Any>?
    ): Any? {
        try {
            val method: Method = clazz.getDeclaredMethod(method_name, *pareTyples)
            method.setAccessible(true)
            return method.invoke(null, pareVaules)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }


    //简写版本
    fun getFieldObject(obj: Any, filedName: String?): Any? {
        return getFieldObject(obj.javaClass, obj, filedName)
    }

    fun getFieldObject(className: String?, obj: Any?, filedName: String?): Any? {
        try {
            val obj_class = Class.forName(className)
            return getFieldObject(obj_class, obj, filedName)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
        return null
    }

    fun getFieldObject(clazz: Class<*>, obj: Any?, filedName: String?): Any? {
        try {
            val field: Field = clazz.getDeclaredField(filedName)
            field.isAccessible = true
            return field.get(obj)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    //简写版本
    fun setFieldObject(obj: Any, filedName: String?, filedVaule: Any?) {
        setFieldObject(obj.javaClass, obj, filedName, filedVaule)
    }

    fun setFieldObject(clazz: Class<*>, obj: Any?, filedName: String?, filedVaule: Any?) {
        try {
            val field: Field = clazz.getDeclaredField(filedName)
            field.setAccessible(true)
            field.set(obj, filedVaule)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun setFieldObject(className: String?, obj: Any?, filedName: String?, filedVaule: Any?) {
        try {
            val obj_class = Class.forName(className)
            setFieldObject(obj_class, obj, filedName, filedVaule)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }
    }


    fun getStaticFieldObject(className: String?, filedName: String?): Any? {
        return getFieldObject(className, null, filedName)
    }

    fun getStaticFieldObject(clazz: Class<*>, filedName: String?): Any? {
        return getFieldObject(clazz, null, filedName)
    }

    fun setStaticFieldObject(classname: String?, filedName: String?, filedVaule: Any?) {
        setFieldObject(classname, null, filedName, filedVaule)
    }

    fun setStaticFieldObject(clazz: Class<*>, filedName: String?, filedVaule: Any?) {
        setFieldObject(clazz, null, filedName, filedVaule)
    }
}
复制代码

1.2 反射技术

  • 根据一个字符串得到一个类的对象。
  • 获取一个类的所有公用或私有、静态或实例的字段、方法、属性。
  • 对泛型类的反射。
1.2.1 根据一个字符串得到一个类

得到一个类或者属性是我们在使用动态代理的时候大量的用作参数,所以必须要知道的

  • getClass
String str = "123";
Class clazz = str.getClass();
复制代码
  • Class.forName()

在开发中使用比较多

try {
    Class<?> aClass = Class.forName("");
    // 获取父类对象
    Object o = aClass.getSuperclass();
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
  • Class 属性

每个类都有class 属性,通过class 属性可以得到类的类型

Class<String> stringClass = String.class;
Class<Integer> integerClass = int.class;
复制代码
  • TYPE 属性

基本数据类型都有自己的TYPE 属性 本质上是返回一个Class 对象

/*
 * Return the runtime's Class object for the named
 * primitive type.
 */
@FastNative
static native Class<?> getPrimitiveClass(String name);getPrimitiveClass
复制代码

属性的TYPE

Class<Boolean> type = Boolean.TYPE;
Class<Double> doubleClass = Double.TYPE;
复制代码

1.2.2 获取类成员

在1.2.1 中获取到了一个类,那在现实开发中,类的成员才是我们真正操作的东西

  • 获取类的构造函数

获取类的构造函数包含两种类型,即有参、无参。获取方法有两种,即public、private

演示类

/**
 * @author: kpa
 * @time: 2021/4/21
 * @email: billkp@yeah.net
 **/
public class Test {
    private String name;
    public Test(String name) {
        this.name = name;
    }
    public Test() {
    }
    private Test(String name, String args1) {
    }
}
复制代码
  1. 获取类的所有构造函数
Test test = new Test();
Class<? extends Test> testClass = test.getClass();
// getDeclaredConstructors 获取所有的构造方法
Constructor<?>[] constructors = testClass.getDeclaredConstructors();
复制代码
  1. 获取类的某个构造函数
Constructor<? extends Test> declare = testClass.getDeclaredConstructor();

//获取有参数的构造函数
Class<String> aClass = String.class;
Constructor<? extends Test> declare = testClass.getDeclaredConstructor(aClass);
// 私有构造函数 并调用
Class[] params = {String.class, String.class};
Constructor<? extends Test> constructor = testClass.getDeclaredConstructor(params);
try {
    Object instance = constructor.newInstance("kpa", "test");
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
  1. 调用构造函数
Class<?> aClass = Class.forName("");
// 调用构造函数,获取类的实例
Object o1 = aClass.newInstance();
复制代码
  • 获取类的方法

根据上面获取构造函数的方式,通过getXXX ,就可以得到自己想要的方法,getMethodX相关

try {
// 获取私有方法并且调用改方法
    Object instance = constructor.newInstance("kpa", "test");
    Class p = String.class;
    Method method = testClass.getDeclaredMethod("test", p);
    method.setAccessible(true);
    Object value = "我是谁?";
    method.invoke(instance, value);
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
  • 获取类的字段

根据上面的经验,获取字段肯定是get Field相关的方法,自己试一下就知道了

1.2.3 对泛型类的反射

示例类:

这个代码不仅有反射,还是一个单例

public abstract class Test1<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}
复制代码

对于单例,我们知道的他的对象是唯一的,那我们肯定不能再进行newInstance了

try {
// 取出单例中的mInstance 就拿到了单例的对象 注意Class<?>
    Class<?> aClass1 = Class.forName("");
    Field mInstance = aClass1.getDeclaredField("mInstance");
    mInstance.setAccessible(true);
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
文章分类
Android
文章标签