Kotlin中的反射

博客地址sguotao.topjava

Java中的反射機制,使得咱們能夠在運行期獲取Java類的字節碼文件中的構造函數,成員變量,成員函數等信息。這一特性使得反射機制被經常用在框架中,想要比較系統的瞭解Kotlin中的反射,先從Java的反射提及。框架

Java中的反射

一般咱們寫好的.java源碼文件,通過javac的編譯,最終生成了.class字節碼文件。這些字節碼文件是與平臺無關的,使用時經過Classloader去加載這些.class字節碼文件,從而讓程序按照咱們編寫好的業務邏輯運行。Java的反射主要是從這些.class文件中獲取咱們想要獲得的內容,那麼Java中的反射可以獲得哪些內容呢?ide

獲取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,獲取成員變量概括起來有如下四種方式: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中,字節碼對應的類是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就須要幾百甚至上千微秒,若是是經過反射訪問對象或構造屬性,甚至須要上萬微秒,對此,官方給出的解釋是,如今尚未精力進行優化,相信後續的版本中,效率問題會有所改善。

參考連接

  1. Kotlin Bootcamp for Programmers
  2. Kotlin Koans
相關文章
相關標籤/搜索