博客地址sguotao.topjava
Java中的反射机制,使得咱们能够在运行期获取Java类的字节码文件中的构造函数,成员变量,成员函数等信息。这一特性使得反射机制被经常用在框架中,想要比较系统的了解Kotlin中的反射,先从Java的反射提及。框架
一般咱们写好的.java源码文件,通过javac的编译,最终生成了.class字节码文件。这些字节码文件是与平台无关的,使用时经过Classloader去加载这些.class字节码文件,从而让程序按照咱们编写好的业务逻辑运行。Java的反射主要是从这些.class文件中获取咱们想要获得的内容,那么Java中的反射可以获得哪些内容呢?ide
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();
复制代码
获取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,获取成员变量概括起来有如下四种方式:ui
//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种方式:this
// 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种方法:spa
//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接口,获取类的接口和基类信息有下面两个方法:ssr
// 获取实现的所有接口
public Type[] getGenericInterfaces()
// 获取基类
public Type getGenericSuperclass() 复制代码
获取类的其它描述信息。code
//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.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中声明的一些关于反射的方法了,那么都有哪些方法呢?
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<*>?
复制代码
在Kotlin1.1中若是反射String,Map,List等类型时,会抛出一个built-in Kotlin Types的异常,这是由于在Kotlin1.1版本中尚未对这些类型添加支持,在Kotlin1.2版本中,这个问题已经解决。
Kotlin关于反射的内容都放在kotlin-reflect的jar包中,这个jar包有2.6M,对于移动端开发,须要占用必定的内存空间。
最后就是关于Kotlin反射的效率问题,在Java中反射大概须要几十微秒,在Kotlin就须要几百甚至上千微秒,若是是经过反射访问对象或构造属性,甚至须要上万微秒,对此,官方给出的解释是,如今尚未精力进行优化,相信后续的版本中,效率问题会有所改善。