在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ 在Java中調(diào)用Kotlin代碼
Kotlin內(nèi)聯(lián)函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(Eclipse)
Kotlin調(diào)用Java代碼
Kotlin使用Ant
Kotlin編譯器插件
Kotlin相等性
Kotlin JavaScript模塊
編寫Kotlin代碼文檔
Kotlin返回和跳轉(zhuǎn)
Kotlin異常處理
Kotlin可見性修飾符
Kotlin委托
Kotlin委托屬性
Kotlin編碼約定/編碼風(fēng)格
Kotlin基礎(chǔ)語法
使用Kotlin進行服務(wù)器端開發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語言有哪些優(yōu)點?
Kotlin JavaScript反射
Kotlin 是什么?
Kotlin泛型
Kotlin慣用語法
Kotlin與OSGi
Kotlin數(shù)據(jù)類型
Kotlin是面向?qū)ο筮€是函數(shù)式語言?
Kotlin動態(tài)類型
Kotlin協(xié)程
Kotlin操作符符重載
Kotlin使用Gradle
Kotlin密封類
Kotlin兼容性
Kotlin集合
Kotlin調(diào)用JavaScript
Kotlin null值安全
Kotlin函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(IntelliJ IDEA)
Kotlin嵌套類
Kotlin控制流程
Kotlin和Java語言比較
Kotlin 與 Java 語言兼容嗎?
Kotlin教程
Kotlin類和繼承
Kotlin對象表達式和對象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達式
Kotlin是免費的嗎?
Kotlin包
使用Kotlin進行Android開發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達式
使用Kotlin進行JavaScript開發(fā)
Kotlin擴展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

在Java中調(diào)用Kotlin代碼

Java 可以輕松調(diào)用 Kotlin 代碼。

屬性

Kotlin 屬性會編譯成以下 Java 元素:

  • 一個 getter 方法,名稱通過加前綴 get 算出;
  • 一個 setter 方法,名稱通過加前綴 set 算出(只適用于 var 屬性);
  • 一個私有字段,與屬性名稱相同(僅適用于具有幕后字段的屬性)。

例如,var firstName: String 編譯成以下 Java 聲明:

private String firstName;

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

如果屬性的名稱以 is 開頭,則使用不同的名稱映射規(guī)則:getter 的名稱
與屬性名稱相同,并且 setter 的名稱是通過將 is 替換為 set 獲得。
例如,對于屬性 isOpen,其 getter 會稱做 isOpen(),而其 setter 會稱做 setOpen()。
這一規(guī)則適用于任何類型的屬性,并不僅限于 Boolean。

包級函數(shù)

org.foo.bar 包內(nèi)的 example.kt 文件中聲明的所有的函數(shù)和屬性,包括擴展函數(shù),
都編譯成一個名為 org.foo.bar.ExampleKt 的 Java 類的靜態(tài)方法。

// example.kt
package demo

class Foo

fun bar() {
}
// Java
new demo.Foo();
demo.ExampleKt.bar();

可以使用 @JvmName 注解修改生成的 Java 類的類名:

@file:JvmName("DemoUtils")

package demo

class Foo

fun bar() {
}
// Java
new demo.Foo();
demo.DemoUtils.bar();

如果多個文件中生成了相同的 Java 類名(包名相同并且類名相同或者有相同的
@JvmName 注解)通常是錯誤的。然而,編譯器能夠生成一個單一的 Java 外觀
類,它具有指定的名稱且包含來自所有文件中具有該名稱的所有聲明。
要啟用生成這樣的外觀,請在所有相關(guān)文件中使用 @JvmMultifileClass 注解。

// oldutils.kt
@file:JvmName("Utils")
@file:JvmMultifileClass

package demo

fun foo() {
}
// newutils.kt
@file:JvmName("Utils")
@file:JvmMultifileClass

package demo

fun bar() {
}
// Java
demo.Utils.foo();
demo.Utils.bar();

實例字段

如果需要在 Java 中將 Kotlin 屬性作為字段暴露,那就需要使用 @JvmField 注解對其標注。
該字段將具有與底層屬性相同的可見性。如果一個屬性有幕后字段(backing field)、非私有、沒有 open
/override 或者 const 修飾符并且不是被委托的屬性,那么你可以用 @JvmField 注解該屬性。

class C(id: String) {
    @JvmField val ID = id
}
// Java
class JavaClient {
    public String getID(C c) {
        return c.ID;
    }
}

延遲初始化的屬性(在Java中)也會暴露為字段。
該字段的可見性與 lateinit 屬性的 setter 相同。

靜態(tài)字段

在命名對象或伴生對象中聲明的 Kotlin 屬性會在該命名對象或包含伴生對象的類中
具有靜態(tài)幕后字段。

通常這些字段是私有的,但可以通過以下方式之一暴露出來:

  • @JvmField 注解;
  • lateinit 修飾符;
  • const 修飾符。

使用 @JvmField 標注這樣的屬性使其成為與屬性本身具有相同可見性的靜態(tài)字段。

class Key(val value: Int) {
    companion object {
        @JvmField
        val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
    }
}
// Java
Key.COMPARATOR.compare(key1, key2);
// Key 類中的 public static final 字段

在命名對象或者伴生對象中的一個延遲初始化的屬性
具有與屬性 setter 相同可見性的靜態(tài)幕后字段。

object Singleton {
    lateinit var provider: Provider
}
// Java
Singleton.provider = new Provider();
// 在 Singleton 類中的 public static 非-final 字段

const 標注的(在類中以及在頂層的)屬性在 Java 中會成為靜態(tài)字段:

// 文件 example.kt

object Obj {
    const val CONST = 1
}

class C {
    companion object {
        const val VERSION = 9
    }
}

const val MAX = 239

在 Java 中:

int c = Obj.CONST;
int d = ExampleKt.MAX;
int v = C.VERSION;

靜態(tài)方法

如上所述,Kotlin 將包級函數(shù)表示為靜態(tài)方法。
Kotlin 還可以為命名對象或伴生對象中定義的函數(shù)生成靜態(tài)方法,如果你將這些函數(shù)標注為 @JvmStatic 的話。
如果你使用該注解,編譯器既會在相應(yīng)對象的類中生成靜態(tài)方法,也會在對象自身中生成實例方法。
例如:

class C {
    companion object {
        @JvmStatic fun foo() {}
        fun bar() {}
    }
}

現(xiàn)在,foo() 在 Java 中是靜態(tài)的,而 bar() 不是:

C.foo(); // 沒問題
C.bar(); // 錯誤:不是一個靜態(tài)方法
C.Companion.foo(); // 保留實例方法
C.Companion.bar(); // 唯一的工作方式

對于命名對象也同樣:

object Obj {
    @JvmStatic fun foo() {}
    fun bar() {}
}

在 Java 中:

Obj.foo(); // 沒問題
Obj.bar(); // 錯誤
Obj.INSTANCE.bar(); // 沒問題,通過單例實例調(diào)用
Obj.INSTANCE.foo(); // 也沒問題

@JvmStatic 注解也可以應(yīng)用于對象或伴生對象的屬性,
使其 getter 和 setter 方法在該對象或包含該伴生對象的類中是靜態(tài)成員。

可見性

Kotlin 的可見性以下列方式映射到 Java:

  • private 成員編譯成 private 成員;
  • private 的頂層聲明編譯成包級局部聲明;
  • protected 保持 protected(注意 Java 允許訪問同一個包中其他類的受保護成員,
    而 Kotlin 不能,所以 Java 類會訪問更廣泛的代碼);
  • internal 聲明會成為 Java 中的 publicinternal 類的成員會通過名字修飾,使其
    更難以在 Java 中意外使用到,并且根據(jù) Kotlin 規(guī)則使其允許重載相同簽名的成員
    而互不可見;
  • public 保持 public。

KClass

有時你需要調(diào)用有 KClass 類型參數(shù)的 Kotlin 方法。
因為沒有從 ClassKClass 的自動轉(zhuǎn)換,所以你必須通過調(diào)用
Class<T>.kotlin 擴展屬性的等價形式來手動進行轉(zhuǎn)換:

kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class)

@JvmName 解決簽名沖突

有時我們想讓一個 Kotlin 中的命名函數(shù)在字節(jié)碼中有另外一個 JVM 名稱。
最突出的例子是由于類型擦除引發(fā)的:

fun List<String>.filterValid(): List<String>
fun List<Int>.filterValid(): List<Int>

這兩個函數(shù)不能同時定義,因為它們的 JVM 簽名是一樣的:filterValid(Ljava/util/List;)Ljava/util/List;。
如果我們真的希望它們在 Kotlin 中用相同名稱,我們需要用 @JvmName 去標注其中的一個(或兩個),并指定不同的名稱作為參數(shù):

fun List<String>.filterValid(): List<String>

@JvmName("filterValidInt")
fun List<Int>.filterValid(): List<Int>

在 Kotlin 中它們可以用相同的名稱 filterValid 來訪問,而在 Java 中,它們分別是 filterValidfilterValidInt。

同樣的技巧也適用于屬性 x 和函數(shù) getX() 共存:

val x: Int
    @JvmName("getX_prop")
    get() = 15

fun getX() = 10

生成重載

通常,如果你寫一個有默認參數(shù)值的 Kotlin 方法,在 Java 中只會有一個所有參數(shù)都存在的完整參數(shù)
簽名的方法可見,如果希望向 Java 調(diào)用者暴露多個重載,可以使用
@JvmOverloads 注解。

@JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") {
    ……
}

對于每一個有默認值的參數(shù),都會生成一個額外的重載,這個重載會把這個參數(shù)和
它右邊的所有參數(shù)都移除掉。在上例中,會生成以下方法

// Java
void f(String a, int b, String c) { }
void f(String a, int b) { }
void f(String a) { }

該注解也適用于構(gòu)造函數(shù)、靜態(tài)方法等。它不能用于抽象方法,包括
在接口中定義的方法。

請注意,如次構(gòu)造函數(shù)中所述,如果一個類的所有構(gòu)造函數(shù)參數(shù)都有默認
值,那么會為其生成一個公有的無參構(gòu)造函數(shù)。這就算
沒有 @JvmOverloads 注解也有效。

受檢異常

如上所述,Kotlin 沒有受檢異常。
所以,通常 Kotlin 函數(shù)的 Java 簽名不會聲明拋出異常。
于是如果我們有一個這樣的 Kotlin 函數(shù):

// example.kt
package demo

fun foo() {
    throw IOException()
}

然后我們想要在 Java 中調(diào)用它并捕捉這個異常:

// Java
try {
  demo.Example.foo();
}
catch (IOException e) { // 錯誤:foo() 未在 throws 列表中聲明 IOException
  // ……
}

因為 foo() 沒有聲明 IOException,我們從 Java 編譯器得到了一個報錯消息。
為了解決這個問題,要在 Kotlin 中使用 @Throws 注解。

@Throws(IOException::class)
fun foo() {
    throw IOException()
}

空安全性

當從 Java 中調(diào)用 Kotlin 函數(shù)時,沒人阻止我們將 null{: .keyword } 作為非空參數(shù)傳遞。
這就是為什么 Kotlin 給所有期望非空參數(shù)的公有函數(shù)生成運行時檢測。
這樣我們就能在 Java 代碼里立即得到 NullPointerException

型變的泛型

當 Kotlin 的類使用了聲明處型變,有兩種選擇
可以從 Java 代碼中看到它們的用法。讓我們假設(shè)我們有以下類和兩個使用它的函數(shù):

class Box<out T>(val value: T)

interface Base
class Derived : Base

fun boxDerived(value: Derived): Box<Derived> = Box(value)
fun unboxBase(box: Box<Base>): Base = box.value

一種看似理所當然地將這倆函數(shù)轉(zhuǎn)換成 Java 代碼的方式可能會是:

Box<Derived> boxDerived(Derived value) { …… }
Base unboxBase(Box<Base> box) { …… }

問題是,在 Kotlin 中我們可以這樣寫 unboxBase(boxDerived("s")),但是在 Java 中是行不通的,因為在 Java 中
Box 在其泛型參數(shù) T 上是不型變的,于是 Box<Derived> 并不是 Box<Base> 的子類。
要使其在 Java 中工作,我們按以下這樣定義 unboxBase

Base unboxBase(Box<? extends Base> box) { …… }

這里我們使用 Java 的通配符類型(? extends Base)來
通過使用處型變來模擬聲明處型變,因為在 Java 中只能這樣。

當它作為參數(shù)出現(xiàn)時,為了讓 Kotlin 的 API 在 Java 中工作,對于協(xié)變定義的 Box 我們生成 Box<Super> 作為 Box<? extends Super>
(或者對于逆變定義的 Foo 生成 Foo<? super Bar>)。當它是一個返回值時,
我們不生成通配符,因為否則 Java 客戶端將必須處理它們(并且它違反常用
Java 編碼風(fēng)格)。因此,我們的示例中的對應(yīng)函數(shù)實際上翻譯如下:

// 作為返回類型——沒有通配符
Box<Derived> boxDerived(Derived value) { …… }

// 作為參數(shù)——有通配符
Base unboxBase(Box<? extends Base> box) { …… }

注意:當參數(shù)類型是 final 時,生成通配符通常沒有意義,所以無論在什么地方 Box<String>
始終轉(zhuǎn)換為 Box<String>。

如果我們在默認不生成通配符的地方需要通配符,我們可以使用 @JvmWildcard 注解:

fun boxDerived(value: Derived): Box<@JvmWildcard Derived> = Box(value)
// 將被轉(zhuǎn)換成
// Box<? extends Derived> boxDerived(Derived value) { …… }

另一方面,如果我們根本不需要默認的通配符轉(zhuǎn)換,我們可以使用@JvmSuppressWildcards

fun unboxBase(box: Box<@JvmSuppressWildcards Base>): Base = box.value
// 會翻譯成
// Base unboxBase(Box<Base> box) { …… }

注意:@JvmSuppressWildcards 不僅可用于單個類型參數(shù),還可用于整個聲明(如
函數(shù)或類),從而抑制其中的所有通配符。

Nothing 類型翻譯

類型 Nothing 是特殊的,因為它在 Java 中沒有自然的對應(yīng)。確實,每個 Java 引用類型,包括
java.lang.Void 都可以接受 null 值,但是 Nothing 不行。因此,這種類型不能在 Java 世界中
準確表示。這就是為什么在使用 Nothing 參數(shù)的地方 Kotlin 生成一個原始類型:

fun emptyList(): List<Nothing> = listOf()
// 會翻譯成
// List emptyList() { …… }

上一篇:Kotlin與OSGi下一篇:Kotlin使用Gradle