Kotlin/Java中的反射詳解

什么是反射

反射是一種計(jì)算機(jī)處理方式诀豁。有程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的這種能力阱驾。能提供封裝程序集就谜、類型的對(duì)象。
對(duì)于Java這種OOP語(yǔ)言來(lái)講,運(yùn)行狀態(tài)中里覆,我們可以根據(jù)“類的部分信息”來(lái)還原“類的全部信息”,這就是Java中的反射吁伺。

Java虛擬機(jī)的體系結(jié)構(gòu)

Java虛擬機(jī)屏蔽了與具體操作系統(tǒng)平臺(tái)相關(guān)的信息,使得Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼)租谈,就可以在多種平臺(tái)上不加修改地運(yùn)行篮奄。通俗地說(shuō)Java虛擬機(jī)就是處理Java程序(確切地說(shuō)是Java字節(jié)碼)的虛擬機(jī)。
作為虛擬機(jī)割去,JVM的結(jié)構(gòu)和常見(jiàn)的操作系統(tǒng)一致窟却,有著自己的堆、棧呻逆、方法區(qū)夸赫、PC計(jì)數(shù)器和指令系統(tǒng)。它的結(jié)構(gòu)如下圖所示:
這里我們暫時(shí)不去談?lì)惣虞d子系統(tǒng)與執(zhí)行引擎咖城,只談一下Java運(yùn)行時(shí)的數(shù)據(jù)區(qū)茬腿,它由五個(gè)部分組成:


image.png

(1)程序計(jì)數(shù)器(線程私有)
程序計(jì)數(shù)器是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器呼奢,字節(jié)碼解釋器工作時(shí)就是通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,
分支切平、循環(huán)握础、跳轉(zhuǎn)、異常處理悴品、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器來(lái)完成禀综。
在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對(duì)于多核處理器來(lái)說(shuō)是一個(gè)內(nèi)核)只會(huì)執(zhí)行一條線程中的指令苔严。
因此定枷,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的線程計(jì)數(shù)器届氢,各條線程之間的計(jì)數(shù)器互不影響欠窒,獨(dú)立存儲(chǔ)尊蚁。
(2)虛擬機(jī)棧(線程私有)
在Java(或者其他JVM的語(yǔ)言)每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表燕雁、操作數(shù)棧、動(dòng)態(tài)鏈接抬探、方法出口等信息絮供。
每一個(gè)方法被調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程茶敏。
Java虛擬機(jī)棧存放局部變量表壤靶,如編譯期可知的各種基本數(shù)據(jù)類型(boolean、byte惊搏、char贮乳、short、int恬惯、float向拆、long、double)酪耳、對(duì)象引用(reference類型浓恳,它不等同于對(duì)象本身,根據(jù)不同的虛擬機(jī)實(shí)現(xiàn)碗暗,它可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔樉苯部赡苤赶蛞粋€(gè)代表對(duì)象的句柄或者與此對(duì)象相關(guān)的位置)和returnAddress類型(指向了一條字節(jié)碼指令的地址)。
這也導(dǎo)致在Java中匿名內(nèi)部類來(lái)自外部閉包環(huán)境的自由變量必須是final的(Java編譯器是capture-by-value模式)言疗,不過(guò)在Kotlin中則沒(méi)有此限制晴圾,它通過(guò)自動(dòng)包裝實(shí)現(xiàn)了capture-by-reference(所以它沒(méi)有基本類型)。
(3)本地方法棧(線程私有)
與虛擬機(jī)棧的作用相似噪奄,其區(qū)別為虛擬機(jī)棧執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)死姚,而本地方法棧則是為虛擬機(jī)所使用的Native方法人乓。
(4)堆(線程共享)
是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域都毒,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建色罚。此內(nèi)存區(qū)域唯一的目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存温鸽。
Java堆是垃圾收集器管理的主要區(qū)域保屯,因此很多時(shí)候也被稱為“GC堆”(Garbage Collected Heap)。由于現(xiàn)在收集器基本都是采用的分代收集算法涤垫,所以Java堆中還可以細(xì)分為:新生代和老年代姑尺。
(5)方法區(qū)(線程共享)
方法區(qū)用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量蝠猬、靜態(tài)變量切蟋、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
具體來(lái)講榆芦,對(duì)于我們?cè)贘ava程序中使用的每一個(gè)類柄粹,它都會(huì)在方法區(qū)生成一個(gè)對(duì)應(yīng)的class文件,這個(gè)文件記錄的信息有:
(如果你想了解更多的信息,可以參考http://blog.csdn.net/luanlouis/article/details/39892027)匆绣,這里只簡(jiǎn)單的說(shuō)明一下驻右。
1.類信息
2.字段信息
3.方法信息
4.常量池
5.類變量(靜態(tài)static字段,或者companion object)
6.classLoader的引用
7.class對(duì)象的引用
8.方法表
正由于在JVM的方法區(qū)中實(shí)時(shí)記錄了這些信息,我們才可以在運(yùn)行時(shí)獲取類的全部信息崎淳,其關(guān)鍵在于獲取其對(duì)應(yīng)的Class對(duì)象堪夭。

獲取Class對(duì)象

在Java中,獲取Class對(duì)象有以下幾種方法:
1: Class.forName("類名字符串") (注意:類名字符串必須是全稱拣凹,包名+類名)
2: 類名.class
3: 實(shí)例對(duì)象.getClass()

    public void getClassTest()
    {
       try{
           Class baseInfo = Class.forName("com.suiseiseki.www.BaseInfo");
           Class object = Object.class;
           Class date = (new Date()).getClass();
           Class testclass = this.getClass();
       }
       catch (Exception e)
       {
           e.printStackTrace();
       }
    }

還原類的信息

獲取類的構(gòu)造器

Java提供以下Api用于獲取類的構(gòu)造方法:

// 獲取“參數(shù)是parameterTypes”的public的構(gòu)造函數(shù)
public Constructor    getConstructor(Class[] parameterTypes)
// 獲取全部的public的構(gòu)造函數(shù)
public Constructor[]    getConstructors()
// 獲取“參數(shù)是parameterTypes”的森爽,并且是類自身聲明的構(gòu)造函數(shù),包含public嚣镜、protected和private方法爬迟。
public Constructor    getDeclaredConstructor(Class[] parameterTypes)
// 獲取類自身聲明的全部的構(gòu)造函數(shù),包含public菊匿、protected和private方法付呕。
public Constructor[]    getDeclaredConstructors()
// 如果這個(gè)類是“其它類的構(gòu)造函數(shù)中的內(nèi)部類”,調(diào)用getEnclosingConstructor()就是這個(gè)類所在的構(gòu)造函數(shù)跌捆;若不存在凡涩,返回null。
public Constructor    getEnclosingConstructor()

例如:

public class Test1 {

    public void testConstructor()
    {
       try{
           Class c = Country.class;
           //獲取public的無(wú)參數(shù)構(gòu)造器
           Constructor origin = c.getDeclaredConstructor();
           //獲取private的構(gòu)造器(注意int.class不是Integer.class)
           Constructor cst2 = c.getDeclaredConstructor(new Class[]{int.class,int.class});
           //構(gòu)造器是private的疹蛉,所以這里要設(shè)置為可訪問(wèn)
           cst2.setAccessible(true);

           Country c1 = (Country)origin.newInstance();
           Country c2 = (Country)cst2.newInstance(30,100);
           System.out.println(c1);
           System.out.println(c2);
       }
       catch (Exception e) {}
    }
}
class Country{
    public int pop;
    public int money;
    public Country(){
        pop = 0;
        money = 0;
    }
    private Country(int pop,int money)
    {
        this.pop = pop;
        this.money = money;
    }
    @Override
    public String toString()
    {
        return "pop "+pop+" money: "+money;
    }

    public void doublePop()
    {
        this.pop = this.pop * 2;
    }

    private int multiMoney(int n)
    {
        this.money = this.money*n;
        return this.money;
    }

}

在獲取到構(gòu)造器后活箕,可以調(diào)用構(gòu)造器的newInstance創(chuàng)建對(duì)象。例子中可以看到,反射是可以訪問(wèn)類的private域的育韩,而且還可以修改它克蚂,使用被隱藏的構(gòu)造器。

獲取類的方法

在Java中筋讨,方法是作為Method對(duì)象包裝的埃叭,獲取類的方法對(duì)象的Api如下:

// 獲取“名稱是name,參數(shù)是parameterTypes”的public的函數(shù)(包括從基類繼承的悉罕、從接口實(shí)現(xiàn)的所有public函數(shù))
public Method    getMethod(String name, Class[] parameterTypes)
// 獲取全部的public的函數(shù)(包括從基類繼承的赤屋、從接口實(shí)現(xiàn)的所有public函數(shù))
public Method[]    getMethods()
// 獲取“名稱是name,參數(shù)是parameterTypes”壁袄,并且是類自身聲明的函數(shù)类早,包含public、protected和private方法嗜逻。
public Method    getDeclaredMethod(String name, Class[] parameterTypes)
// 獲取全部的類自身聲明的函數(shù)涩僻,包含public、protected和private方法栈顷。
public Method[]    getDeclaredMethods()
// 如果這個(gè)類是“其它類中某個(gè)方法的內(nèi)部類”逆日,調(diào)用getEnclosingMethod()就是這個(gè)類所在的方法;若不存在萄凤,返回null室抽。
public Method    getEnclosingMethod()

例如,以下方法獲取方法并調(diào)用:

    public void testMethod()
    {
        try{
            Class c = Country.class;
            Country country3 = new Country();
            country3.money = 100;
            country3.pop = 3;
            //獲取public方法(無(wú)參數(shù)靡努,無(wú)返回值)
            Method mDoublePop = c.getMethod("doublePop",new Class[]{});
            //調(diào)用invoke執(zhí)行方法坪圾,需要傳入一個(gè)該類的對(duì)象
            mDoublePop.invoke(country3);
            System.out.println(country3);
            //獲取public方法(有參數(shù),有返回值)
            Method mMultimoney = c.getMethod("multiMoney", new Class[]{int.class});
            mMultimoney.setAccessible(true);
            mMultimoney.invoke(country3,42);
            System.out.println(country3);
        }
        catch (Exception e) {}
    }

對(duì)應(yīng)方法:

    public void doublePop()
    {
        this.pop = this.pop * 2;
    }

    private int multiMoney(int n)
    {
        this.money = this.money*n;
        return this.money;
    }

獲取類的成員變量

在Java中颤难,成員變量稱為Field對(duì)象,獲取類成員變量的Api如下:

// 獲取“名稱是name”的public的成員變量(包括從基類繼承的、從接口實(shí)現(xiàn)的所有public成員變量)
public Field    getField(String name)
// 獲取全部的public成員變量(包括從基類繼承的已维、從接口實(shí)現(xiàn)的所有public成員變量)
public Field[]    getFields()
// 獲取“名稱是name”行嗤,并且是類自身聲明的成員變量,包含public垛耳、protected和private成員變量栅屏。
public Field    getDeclaredField(String name)
// 獲取全部的類自身聲明的成員變量,包含public堂鲜、protected和private成員變量栈雳。
public Field[]    getDeclaredFields()

例如:

    public void fieldTest()
    {
        try{
            Class c = Country.class;
            Country country4 = new Country();
            country4.money = 100;
            country4.pop = 3;

            Field fPop = c.getField("pop");
            fPop.set(42,country4);
            System.out.println(country4);
        }
        catch (Exception e) {}
    }

注意權(quán)限的問(wèn)題,如果沒(méi)有權(quán)限缔莲,需要setAccessible(true)哥纫,否則會(huì)拋出異常

類的其它信息

1.注解

// 獲取類的"annotationClass"類型的注解 (包括從基類繼承的、從接口實(shí)現(xiàn)的所有public成員變量)
public Annotation<A>    getAnnotation(Class annotationClass)
// 獲取類的全部注解 (包括從基類繼承的痴奏、從接口實(shí)現(xiàn)的所有public成員變量)
public Annotation[]    getAnnotations()
// 獲取類自身聲明的全部注解 (包含public蛀骇、protected和private成員變量)
public Annotation[]    getDeclaredAnnotations()

現(xiàn)在厌秒,我們可以編寫一些程序來(lái)自動(dòng)處理程序中的注解了,例如根據(jù)注解來(lái)決定是否處理一個(gè)類:

    public void handleMyAnnotation(List<Class> list)
    {
        for(Class clazz : list)
        {
            if(clazz.getAnnotation(MyAnnotation.class))
            {
                println("This class is under Annotation");
            }
        }
    }

很多著名的開源庫(kù)(Dagger2,GSON,Retrofit,AspectJ)等都是通過(guò)反射+注解完成的擅憔,這些庫(kù)在方便了編寫程序的同時(shí)也會(huì)帶來(lái)一些性能開銷(盡管它們自身已經(jīng)盡力地做了優(yōu)化),
反射在把裝載期做的事情搬到了運(yùn)行期鸵闪,因此編譯器沒(méi)法對(duì)反射相關(guān)的代碼做優(yōu)化。

2.接口和基類

// 獲取實(shí)現(xiàn)的全部接口
public Type[]    getGenericInterfaces()
// 獲取基類
public Type    getGenericSuperclass()

注意反射獲取的基類是直接的基類(也就是說(shuō)只能獲取上一級(jí)),要獲取繼承鏈暑诸,需要進(jìn)一步深度遍歷

3.描述性信息

// 獲取“類名”
public String    getSimpleName()
// 獲取“完整類名”
public String    getName()
// 類是不是“枚舉類”
public boolean    isEnum()
// obj是不是類的對(duì)象
public boolean    isInstance(Object obj)
// 類是不是“接口”
public boolean    isInterface()
// 類是不是“本地類”蚌讼。本地類,就是定義在方法內(nèi)部的類。
public boolean    isLocalClass()
// 類是不是“成員類”个榕。成員類,是內(nèi)部類的一種篡石,但是它不是“內(nèi)部類”或“匿名類”。
public boolean    isMemberClass()
// 類是不是“基本類型”笛洛。 基本類型夏志,包括void和boolean、byte苛让、char沟蔑、short、int狱杰、long瘦材、float 和 double這幾種類型。
public boolean    isPrimitive()

在Kotlin中使用Java中的反射

作為基于JVM的語(yǔ)言仿畸,Kotlin當(dāng)然也支持Java語(yǔ)言中原有的反射機(jī)制(而且代碼量往往更少)食棕,通過(guò)類的javaClass實(shí)現(xiàn)。
例如错沽,一個(gè)常見(jiàn)的通過(guò)反射來(lái)獲取R文件中控件的ID描述的程序:

    val viewId : String by lazy {
            val c = R.id()
            val fields = c.javaClass.declaredFields
            val r = fields.find { it.getInt(c) == view.id }?.name?:"Not found"
            r
    }

使用懶加載避免了無(wú)用的性能開銷簿晓。
需要注意的是直接調(diào)用R.id::class獲取的是KClass對(duì)象,它代表Kotlin中反射的入口千埃,要獲取Java的Class對(duì)象憔儿,需要其.java屬性,例如:

        {
            val c = R.id::class
            val fields = c.java.fields
            val r = fields.find { it.getInt(c) == view.id }?.name?:"Not found"
            r
        }

以上兩種方式代表了通過(guò)對(duì)象和類名訪問(wèn)Java原有反射API的方式放可。

Kotlin中的KClass反射

Kotlin是函數(shù)式編程語(yǔ)言谒臼,它有一些獨(dú)有的特性,例如耀里,在Kotlin中的Property往往對(duì)應(yīng)了Java中的Field以及對(duì)應(yīng)的getter/setter,
而函數(shù)本身也具有類型蜈缤,也可以作為變量保存。
要使用Kotlin的反射Api,需要獲取對(duì)應(yīng)的KClass對(duì)象冯挎,可以通過(guò)以下方式:
1.類名::class

val clazz = Country::class

2.對(duì)象.javaclass.kotlin

val clazz = country4.javaClass.kotlin

KClass是一個(gè)泛型接口底哥,它的定義如下:

public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {
    //返回類的名字
    public val simpleName: String?

    //返回類的全包名
    public val qualifiedName: String?

     //返回這個(gè)類可訪問(wèn)的所有函數(shù)和屬性,包括繼承自基類的,但是不包括構(gòu)造器
    override val members: Collection<KCallable<*>>

    //返回這個(gè)類的所有構(gòu)造器
    public val constructors: Collection<KFunction<T>>

     //返回這個(gè)類中定義的其他類叠艳,包括內(nèi)部類(inner class聲明的)和嵌套類(class聲明的)
    public val nestedClasses: Collection<KClass<*>>

     //如果這個(gè)類聲明為object奶陈,則返回其實(shí)例,否則返回null
    public val objectInstance: T?

    // 判斷一個(gè)對(duì)象是否為此類的實(shí)例
    // 和 對(duì)象 is 類名 作用一樣附较,如:  country3 is Country
    @SinceKotlin("1.1")
    public fun isInstance(value: Any?): Boolean

     // 返回這個(gè)類的泛型列表
    @SinceKotlin("1.1")
    public val typeParameters: List<KTypeParameter>

     //以列表的方式依次顯示其直接基類
    @SinceKotlin("1.1")
    public val supertypes: List<KType>

     // 返回這個(gè)類的可見(jiàn)性
    @SinceKotlin("1.1")
    public val visibility: KVisibility?

    // 這個(gè)類是否為final類(PS:在Kotlin中吃粒,類默認(rèn)是final的,除非這個(gè)類聲明為open或者abstract)
    @SinceKotlin("1.1")
    public val isFinal: Boolean

    // 這個(gè)類是否是open的(abstract類也是open的)拒课,表示這個(gè)類可以被繼承
    @SinceKotlin("1.1")
    public val isOpen: Boolean

    //是否為抽象類
    @SinceKotlin("1.1")
    public val isAbstract: Boolean

    //判斷是否為密封類
    /* 密封類:用sealed修飾徐勃,其子類只能在其內(nèi)部定義 */
    @SinceKotlin("1.1")
    public val isSealed: Boolean

     // 判斷類是否為data類
    @SinceKotlin("1.1")
    public val isData: Boolean

     // 判斷類是否為內(nèi)部類(嵌套類為nest,不算)
    @SinceKotlin("1.1")
    public val isInner: Boolean

    //判斷這個(gè)類是否為companion object
    @SinceKotlin("1.1")
    public val isCompanion: Boolean

}

除此之外,KClass還有一些很有用的擴(kuò)展函數(shù)/屬性早像,例如:

//返回其所有的基類
val KClass<*>.allSuperclasses: Collection<KClass<*>>
//返回其companionObject
val KClass<*>.companionObject: KClass<*>?
//返回其聲明的所有函數(shù)
val KClass<*>.declaredFunctions: Collection<KFunction<*>>
//返回其擴(kuò)展函數(shù)和屬性
val KClass<*>.declaredMemberExtensionFunctions: Collection<KFunction<*>>
val <T : Any> KClass<T>.declaredMemberExtensionProperties: Collection<KProperty2<T, *, *>>
//返回其自身聲明的函數(shù)和屬性
val KClass<*>.declaredMemberFunctions: Collection<KFunction<*>>
val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>

其實(shí)還有很多僻肖,這里就不一一列舉了,它們其實(shí)都可以通過(guò)基本Api然后進(jìn)行filter獲得
需要注意的是卢鹦,在函數(shù)作為一等公民以后臀脏,函數(shù)和屬性具有了共同的接口KCallable,允許你調(diào)用其call方法來(lái)使用函數(shù)或者訪問(wèn)屬性的getter:

class DVT {
    fun test()
    {
        val su = Person("su",24)
        val clazz = su.javaClass.kotlin
        val list = clazz.members
        for(calls in list)
        {
            when(calls.name)
            {
                "name" -> print("name is"+calls.call(su))
                "age" -> print("age is"+calls.call(su))
                "selfDescribe" -> calls.call()
            }
        }
    }
}
data class Person(val name : String,var age : Int)
{
    fun selfDescribe() : String
    {
        return "My name is $name,I am $age years old"
    }
}

需要注意冀自,call這個(gè)方法的參數(shù)類型是vararg Any?揉稚,如果你用錯(cuò)誤的類型實(shí)參(數(shù)量不一致或者類型不一致)去調(diào)用是會(huì)報(bào)錯(cuò)的,
為了避免這種情況,你可以用更具體的方式去調(diào)用這個(gè)函數(shù)熬粗。

class DVT {
    fun test()
    {
        val su = Person("su",24)
        val clazz = su.javaClass.kotlin
        val function1 = Person::selfDescribe
        val function2 = Person::grow
        function1.invoke(su)
        function2.invoke(su,1)
    }
}
data class Person(val name : String,var age : Int)
{
    fun selfDescribe() : String
    {
        return "My name is $name,I am $age years old"
    }
    fun grow(a : Int) : Int
    {
        age+=a
        return age
    }
}

function1的類型是KFunction0<String>,function2的類型是KFunction1<Int,Int>,像KFunctionN這樣的接口代表了不同數(shù)量參數(shù)的參數(shù)搀玖,
它們都繼承了KFunction并添加了一個(gè)invoke成員,它擁有數(shù)量剛好的參數(shù)驻呐,包含參數(shù)和返回參數(shù)
這種類型稱為編譯器生成的類型灌诅,你不能找到它們的聲明,你可以使用任意數(shù)量參數(shù)的函數(shù)接口(而不是先聲明一萬(wàn)個(gè)不同參數(shù)數(shù)量的接口)
對(duì)于call函數(shù)含末,它是對(duì)于所有類型通用的手段猜拾,但是不保證安全性。
你也可以反射調(diào)用屬性的getter和setter:

        val ageP = Person::age
        //通過(guò)setter-call調(diào)用(不安全)
        ageP.setter.call(24)
        //通過(guò)set()調(diào)用(安全)
        ageP.set(su,24)
        //通過(guò)getter-call調(diào)用(不安全)
        ageP.getter.call()
        //通過(guò)get調(diào)用(安全)
        ageP.get(su)

所有屬性都是KProperty1的實(shí)例佣盒,它是一個(gè)泛型類KProperty1<R,T>,其中R為接收者類型(文中的Person類),T為屬性類型(文中為Int),
這樣就保證了你對(duì)正確類型的接收者調(diào)用其方法挎袜。
其子類KMutableProperty代表var屬性

兼容問(wèn)題

雖然Kotlin號(hào)稱完全兼容Java,但是從注解和反射的概念來(lái)看沼撕,似乎它并不代表一切Java的工具庫(kù)都可以應(yīng)用到Kotlin中宋雏。
例如通過(guò)對(duì)代碼注解自動(dòng)生成模板代碼的庫(kù)(APT),生成的代碼均為 Java 代碼而非 kt代碼芜飘。對(duì)于一些作用于java文件到class文件轉(zhuǎn)換過(guò)程中的庫(kù)(AspectJ)务豺,實(shí)際上是很無(wú)力的,它不能作用于kt文件,大部分基于這個(gè)過(guò)程的AOP框架都不能正常工作。唯一能正確作用的是.class到.dex轉(zhuǎn)換中的庫(kù)(熱修復(fù),基于Javaassist)嗦明。因此笼沥,如果要引入前兩種第三方庫(kù),需要確認(rèn)它們是否支持Kotlin語(yǔ)言。
對(duì)于代碼注解自動(dòng)生成模板代碼的庫(kù)(Dagger,ButterKnife,DBFlow這些常見(jiàn)的APT庫(kù))奔浅,可以嘗試Kotlin Annotation processing tool馆纳,簡(jiǎn)稱kapt,但是并不保證能完全正常工作

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汹桦,一起剝皮案震驚了整個(gè)濱河市鲁驶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舞骆,老刑警劉巖钥弯,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異督禽,居然都是意外死亡脆霎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門狈惫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)睛蛛,“玉大人,你說(shuō)我怎么就攤上這事胧谈∫渖觯” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵第岖,是天一觀的道長(zhǎng)难菌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蔑滓,這世上最難降的妖魔是什么郊酒? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮键袱,結(jié)果婚禮上燎窘,老公的妹妹穿的比我還像新娘。我一直安慰自己蹄咖,他們只是感情好褐健,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著澜汤,像睡著了一般蚜迅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俊抵,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天谁不,我揣著相機(jī)與錄音,去河邊找鬼徽诲。 笑死刹帕,一個(gè)胖子當(dāng)著我的面吹牛吵血,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播偷溺,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蹋辅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了挫掏?” 一聲冷哼從身側(cè)響起侦另,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尉共,沒(méi)想到半個(gè)月后淋肾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡爸邢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年樊卓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杠河。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碌尔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出券敌,到底是詐尸還是另有隱情唾戚,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布待诅,位于F島的核電站叹坦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏卑雁。R本人自食惡果不足惜募书,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望测蹲。 院中可真熱鬧莹捡,春花似錦、人聲如沸扣甲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琉挖。三九已至启泣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間示辈,已是汗流浹背寥茫。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顽耳,地道東北人坠敷。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像射富,于是被迫代替她去往敵國(guó)和親膝迎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 前言 人生苦多胰耗,快來(lái) Kotlin 限次,快速學(xué)習(xí)Kotlin! 什么是Kotlin柴灯? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,176評(píng)論 9 118
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,867評(píng)論 25 707
  • 什么是反射 反射是一種計(jì)算機(jī)處理方式卖漫。有程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的這種能力赠群。能提供封裝程序集羊始、類型...
    黑心石閱讀 5,319評(píng)論 1 5
  • 真實(shí)案例 “如果藝校是通往完成歌唱家夢(mèng)想的大門,那么160cm的身高就是這扇大門的敲門磚查描,可是突委,我卻連這塊敲門磚都...
    身高管理師閱讀 413評(píng)論 0 0
  • 時(shí)間在走 年齡在長(zhǎng) 懂得的多了 看得的就多了 快樂(lè)越來(lái)越少 我懷念那些年 未來(lái)遙遠(yuǎn)的沒(méi)有形狀 我們單純的沒(méi)有煩惱 ...
    北瑾余生閱讀 120評(píng)論 0 0