Kotlin中的反射机制深入讲解
前言
java中的反射机制,使得我们可以在运行期获取java类的字节码文件中的构造函数,成员变量,成员函数等信息。这一特性使得反射机制被常常用在框架中,想要比较系统的了解kotlin中的反射,先从java的反射说起。
java中的反射
通常我们写好的.java源码文件,经过javac的编译,最终生成了.class字节码文件。这些字节码文件是与平台无关的,使用时通过classloader去加载这些.class字节码文件,从而让程序按照我们编写好的业务逻辑运行。java的反射主要是从这些.class文件中获取我们想要得到的内容,那么java中的反射能够得到哪些内容呢?
获取class对象
java是面向对象的语言,同样的.class字节码文件也不例外,想要获取.class文件中的内容,就要先获取.class文件对应的class对象。java中获取class对象的方式有三种。
//1.class.forname("类名字符串") (注意:类名字符串必须是全称,包名+类名) class baseinfo = class.forname("top.sguotao.reflectionjava"); //2.类名.class class object = object.class; //3.实例对象.getclass() class date = (new date()).getclass(); class testclass = this.getclass();
获取类的构造函数constructor
获取class对象之后,就可以获取其中的构造函数,从而去创建实例对象。类的构造函数对应java.lang.reflect.constructor。获取构造函数归纳起来有以下五种方式:
// 1.获取参数列表是parametertypes,访问控制符是public的构造函数 public constructor getconstructor(class[] parametertypes) // 2.获取所有访问控制符是public的构造函数 public constructor[] getconstructors() // 3.获取参数列表是parametertypes,并且是类自身声明的构造函数,访问控制符包含public、protected和private的函数。 public constructor getdeclaredconstructor(class[] parametertypes) //4.获取类自身声明的全部的构造函数,访问控制符包含public、protected和private的函数。 public constructor[] getdeclaredconstructors() //5.如果类声明在其它类的构造函数中,返回该类所在的构造函数,如果存在则返回,不存在返回null public constructor getenclosingconstructor()
获取类的成员变量
类的成员变量对应的是java.lang.reflect.field,获取成员变量归纳起来有以下四种方式:
//1.获取“名称是name”的public的成员变量(包括从基类继承的、从接口实现的所有public成员变量) public field getfield(string name) //2.获取全部的public成员变量(包括从基类继承的、从接口实现的所有public成员变量) public field[] getfields() //3.获取“名称是name”,并且是类自身声明的成员变量,包含public、protected和private成员变量。 public field getdeclaredfield(string name) //4.获取全部的类自身声明的成员变量,包含public、protected和private成员变量。 public field[] getdeclaredfields()
获取类的成员函数
类的成员函数对应的是java.lang.reflect.method,获取成员函数归纳起来有下面5种方式:
// 1.获取函数名是name,参数是parametertypes的public的函数(包括从基类继承的、从接口实现的所有public函数) public method getmethod(string name, class[] parametertypes) //2.获取全部的public的函数(包括从基类继承的、从接口实现的所有public函数) public method[] getmethods() //3.获取函数名name,参数是parametertypes,并且是类自身声明的函数,包含public、protected和private方法。 public method getdeclaredmethod(string name, class[] parametertypes) //4.获取全部的类自身声明的函数,包含public、protected和private方法。 public method[] getdeclaredmethods() //5.如果这个类是其它类中某个方法的内部类,调用getenclosingmethod()就是这个类所在的方法;若不存在,返回null。 public method getenclosingmethod()
获取类的其它信息
获取类的注解信息,对应的是java.lang.annotation.annotation接口,获取类的注解信息归纳起来有下面3种方法:
//1.获取类的annotationclass类型的注解 (包括从基类继承的、从接口实现的所有public成员变量) public annotation<a> getannotation(class annotationclass) //2.获取类的全部注解 (包括从基类继承的、从接口实现的所有public成员变量) public annotation[] getannotations() //3.获取类自身声明的全部注解 (包含public、protected和private成员变量) public annotation[] getdeclaredannotations()
获取类的接口和基类的信息,对应的是java.lang.reflect.type接口,获取类的接口和基类信息有下面两个方法:
// 获取实现的全部接口 public type[] getgenericinterfaces() // 获取基类 public type getgenericsuperclass()
获取类的其它描述信息。
//1.获取类名 public string getsimplename() //2.获取完整类名 public string getname() //3.判断类是不是枚举类 public boolean isenum() //4.判断obj是不是类的实例对象 public boolean isinstance(object obj) //5.判断类是不是接口 public boolean isinterface() //6.判断类是不是本地类,所谓本地类,就是定义在方法内部的类。 public boolean islocalclass() //7.判断类是不是成员类,所谓成员类,就是常见的内部类,是指不在代码块,构造函数和成员方法中的内部类。 public boolean ismemberclass() //8.判断类是不是基本类型。 基本类型,包括void和boolean、byte、char、short、int、long、float 和 double这几种类型。 public boolean isprimitive()
kotlin中的反射
在kotlin中,字节码对应的类是kotlin.reflect.kclass,因为kotlin百分之百兼容java,所以kotlin中可以使用java中的反射,但是由于kotlin中字节码.class对应的是kclass类,所以如果想要使用java中的反射,需要首先获取class的实例,在kotlin中可以通过以下两种方式来获取class实例。
//1.通过实例.javaclass var hello = helloworld() hello.javaclass //2.通过类kclass类的.java属性 helloworld::class.java
获取了class实例,就可以调用上面介绍的方法,获取各种在java中定义的类的信息了。
当然kotlin中除了可以使用java中的反射以外,还可以使用kotlin中声明的一些方法,当然同java中反射一样,想要使用这些方法,先要获取kclass对象,在kotlin中可以通过以下两种方式获取kclass实例。
//1.通过类::class的方式获取kclass实例 val clazz1: kclass<*> = helloworld::class //2.通过实例.javaclass.kotlin获取kclass实例 var hello = helloworld() val clazz2 = hello.javaclass.kotlin
获取了kclass实例之后,就可以调用kotlin中声明的一些关于反射的方法了,那么都有哪些方法呢?
构造函数constructor
kotlin可以通过下面的方法,获取所有的构造函数。
//返回这个类的所有构造器 public val constructors: collection<kfunction<t>>
成员变量和成员函数
kotlin中获取成员变量和成员函数的方法有6个。
//返回类可访问的所有函数和属性,包括继承自基类的,但是不包括构造器 override val members: collection<kcallable<*>> //返回类声明的所有函数 val kclass<*>.declaredfunctions: collection<kfunction<*>> //返回类的扩展函数 val kclass<*>.declaredmemberextensionfunctions: collection<kfunction<*>> //返回类的扩展属性 val <t : any> kclass<t>.declaredmemberextensionproperties: collection<kproperty2<t, *, *>> //返回类自身声明的成员函数 val kclass<*>.declaredmemberfunctions: collection<kfunction<*>> //返回类自身声明的成员变量(属性) val <t : any> kclass<t>.declaredmemberproperties: collection<kproperty1<t, *>>
类相关信息
可以看到kotlin反射中,可以获取比java反射更多的关于类的信息。
//1.返回类的名字 public val simplename: string? //2.返回类的全包名 public val qualifiedname: string? //3.如果这个类声明为object,则返回其实例,否则返回null public val objectinstance: t? //4.返回类的可见性 @sincekotlin("1.1") public val visibility: kvisibility? //5.判断类是否为final类(在kotlin中,类默认是final的,除非这个类声明为open或者abstract) @sincekotlin("1.1") public val isfinal: boolean //6.判断类是否是open的(abstract类也是open的),表示这个类可以被继承 @sincekotlin("1.1") public val isopen: boolean //7.判断类是否为抽象类 @sincekotlin("1.1") public val isabstract: boolean //8.判断类是否为密封类,密封类:用sealed修饰,其子类只能在其内部定义 @sincekotlin("1.1") public val issealed: boolean //9.判断类是否为data类 @sincekotlin("1.1") public val isdata: boolean //10.判断类是否为成员类 @sincekotlin("1.1") public val isinner: boolean //11.判断类是否为companion object @sincekotlin("1.1") public val iscompanion: boolean //12.返回类中定义的其他类,包括内部类(inner class声明的)和嵌套类(class声明的) public val nestedclasses: collection<kclass<*>> //13.判断一个对象是否为此类的实例 @sincekotlin("1.1") public fun isinstance(value: any?): boolean //14.返回这个类的泛型列表 @sincekotlin("1.1") public val typeparameters: list<ktypeparameter> //15.类其直接基类的列表 @sincekotlin("1.1") public val supertypes: list<ktype> //16.返回类所有的基类 val kclass<*>.allsuperclasses: collection<kclass<*>> //17.返回类的伴生对象companionobject val kclass<*>.companionobject: kclass<*>?
使用kotin中反射注意的问题
在kotlin1.1中如果反射string,map,list等类型时,会抛出一个built-in kotlin types的异常,这是因为在kotlin1.1版本中还没有对这些类型添加支持,在kotlin1.2版本中,这个问题已经解决。
kotlin关于反射的内容都放在kotlin-reflect的jar包中,这个jar包有2.6m,对于移动端开发,需要占用一定的内存空间。
最后就是关于kotlin反射的效率问题,在java中反射大概需要几十微秒,在kotlin就需要几百甚至上千微秒,如果是通过反射访问对象或构造属性,甚至需要上万微秒,对此,官方给出的解释是,现在还没有精力进行优化,相信后续的版本中,效率问题会有所改善。
参考链接
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。