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

鍍金池/ 教程/ Android/ Kotlin調(diào)用Java代碼
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進(jìn)行服務(wù)器端開發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當(dāng)前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語言有哪些優(yōu)點(diǎn)?
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對象表達(dá)式和對象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達(dá)式
Kotlin是免費(fèi)的嗎?
Kotlin包
使用Kotlin進(jìn)行Android開發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達(dá)式
使用Kotlin進(jìn)行JavaScript開發(fā)
Kotlin擴(kuò)展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

Kotlin調(diào)用Java代碼

Kotlin 在設(shè)計時就考慮了 Java 互操作性。可以從 Kotlin 中自然地調(diào)用現(xiàn)存的 Java 代碼,并且在 Java 代碼中也可以
很順利地調(diào)用 Kotlin 代碼。在本節(jié)中我們會介紹從 Kotlin 中調(diào)用 Java 代碼的一些細(xì)節(jié)。

幾乎所有 Java 代碼都可以使用而沒有任何問題

import java.util.*

fun demo(source: List<Int>) {
    val list = ArrayList<Int>()
    // “for”-循環(huán)用于 Java 集合:
    for (item in source) {
        list.add(item)
    }
    // 操作符約定同樣有效:
    for (i in 0..source.size() - 1) {
        list[i] = source[i] // 調(diào)用 get 和 set
    }
}

Getter 和 Setter

遵循 Java 約定的 getter 和 setter 的方法(名稱以 get 開頭的無參數(shù)方法和
set 開頭的單參數(shù)方法)在 Kotlin 中表示為屬性。 例如:

import java.util.Calendar

fun calendarDemo() {
    val calendar = Calendar.getInstance()
    if (calendar.firstDayOfWeek == Calendar.SUNDAY) {  // 調(diào)用 getFirstDayOfWeek()
        calendar.firstDayOfWeek = Calendar.MONDAY       // 調(diào)用 setFirstDayOfWeek()
    }
}

請注意,如果 Java 類只有一個 setter,它在 Kotlin 中不會作為屬性可見,因為 Kotlin 目前不支持只寫(set-only)屬性。

返回 void 的方法

如果一個 Java 方法返回 void,那么從 Kotlin 調(diào)用時中返回 Unit
萬一有人使用其返回值,它將由 Kotlin 編譯器在調(diào)用處賦值,
因為該值本身是預(yù)先知道的(是 Unit)。

將 Kotlin 中是關(guān)鍵字的 Java 標(biāo)識符進(jìn)行轉(zhuǎn)義

一些 Kotlin 關(guān)鍵字在 Java 中是有效標(biāo)識符:in{: .keyword }、 object{: .keyword }、 is{: .keyword } 等等。
如果一個 Java 庫使用了 Kotlin 關(guān)鍵字作為方法,你仍然可以通過反引號(`)字符轉(zhuǎn)義它
來調(diào)用該方法

foo.`is`(bar)

空安全和平臺類型

Java 中的任何引用都可能是 null{: .keyword },這使得 Kotlin 對來自 Java 的對象要求嚴(yán)格空安全是不現(xiàn)實的。
Java 聲明的類型在 Kotlin 中會被特別對待并稱為平臺類型。對這種類型的空檢查會放寬,
因此它們的安全保證與在 Java 中相同(更多請參見下文)。

考慮以下示例:

val list = ArrayList<String>() // 非空(構(gòu)造函數(shù)結(jié)果)
list.add("Item")
val size = list.size() // 非空(原生 int)
val item = list[0] // 推斷為平臺類型(普通 Java 對象)

當(dāng)我們調(diào)用平臺類型變量的方法時,Kotlin 不會在編譯時報告可空性錯誤,
但在運(yùn)行時調(diào)用可能會失敗,因為空指針異常或者 Kotlin 生成的阻止空值傳播的斷言:

item.substring(1) // 允許,如果 item == null 可能會拋出異常

平臺類型是不可標(biāo)示的,意味著不能在語言中明確地寫下它們。
當(dāng)把一個平臺值賦值給一個 Kotlin 變量時,可以依賴類型推斷(該變量會具有推斷出的的平臺類型,
如上例中 item 所具有的類型),或者我們可以選擇我們期望的類型(可空或非空類型均可):

val nullable: String? = item // 允許,沒有問題
val notNull: String = item // 允許,運(yùn)行時可能失敗

如果我們選擇非空類型,編譯器會在賦值時觸發(fā)一個斷言。這防止 Kotlin 的非空變量保存
空值。當(dāng)我們把平臺值傳遞給期待非空值等的 Kotlin 函數(shù)時,也會觸發(fā)斷言。
總的來說,編譯器盡力阻止空值通過程序向遠(yuǎn)傳播(盡管鑒于泛型的原因,有時這
不可能完全消除)。

平臺類型表示法

如上所述,平臺類型不能在程序中顯式表述,因此在語言中沒有相應(yīng)語法。
然而,編譯器和 IDE 有時需要(在錯誤信息中、參數(shù)信息中等)顯示他們,所以我們用
一個助記符來表示他們:

  • T! 表示“T 或者 T?”,
  • (Mutable)Collection<T>! 表示“可以可變或不可變、可空或不可空的 T 的 Java 集合”,
  • Array<(out) T>! 表示“可空或者不可空的 T(或 T 的子類型)的 Java 數(shù)組”

可空性注解

具有可空性注解的Java類型并不表示為平臺類型,而是表示為實際可空或非空的
Kotlin 類型。編譯器支持多種可空性注解,包括:

  • JetBrains
    (org.jetbrains.annotations 包中的 @Nullable@NotNull)
  • Android(com.android.annotationsandroid.support.annotations)
  • JSR-305(javax.annotation)
  • FindBugs(edu.umd.cs.findbugs.annotations)
  • Eclipse(org.eclipse.jdt.annotation)
  • Lombok(lombok.NonNull)。

你可以在 Kotlin 編譯器源代碼中找到完整的列表。

已映射類型

Kotlin 特殊處理一部分 Java 類型。這樣的類型不是“按原樣”從 Java 加載,而是 映射 到相應(yīng)的 Kotlin 類型。
映射只發(fā)生在編譯期間,運(yùn)行時表示保持不變。
Java 的原生類型映射到相應(yīng)的 Kotlin 類型(請記住平臺類型):

Java 類型 Kotlin 類型
byte kotlin.Byte
short kotlin.Short
int kotlin.Int
long kotlin.Long
char kotlin.Char
float kotlin.Float
double kotlin.Double
boolean kotlin.Boolean

{:.zebra}

一些非原生的內(nèi)置類型也會作映射:

Java 類型 Kotlin 類型
java.lang.Object kotlin.Any!
java.lang.Cloneable kotlin.Cloneable!
java.lang.Comparable kotlin.Comparable!
java.lang.Enum kotlin.Enum!
java.lang.Annotation kotlin.Annotation!
java.lang.Deprecated kotlin.Deprecated!
java.lang.CharSequence kotlin.CharSequence!
java.lang.String kotlin.String!
java.lang.Number kotlin.Number!
java.lang.Throwable kotlin.Throwable!

{:.zebra}

Java 的裝箱原始類型映射到可空的 Kotlin 類型:

Java type Kotlin type
java.lang.Byte kotlin.Byte?
java.lang.Short kotlin.Short?
java.lang.Integer kotlin.Int?
java.lang.Long kotlin.Long?
java.lang.Char kotlin.Char?
java.lang.Float kotlin.Float?
java.lang.Double kotlin.Double?
java.lang.Boolean kotlin.Boolean?

{:.zebra}

請注意,用作類型參數(shù)的裝箱原始類型映射到平臺類型:
例如,List<java.lang.Integer> 在 Kotlin 中會成為 List<Int!>。

集合類型在 Kotlin 中可以是只讀的或可變的,因此 Java 集合類型作如下映射:
(下表中的所有 Kotlin 類型都駐留在 kotlin.collections包中):

Java 類型 Kotlin 只讀類型 Kotlin 可變類型 加載的平臺類型
Iterator<T> Iterator<T> MutableIterator<T> (Mutable)Iterator<T>!
Iterable<T> Iterable<T> MutableIterable<T> (Mutable)Iterable<T>!
Collection<T> Collection<T> MutableCollection<T> (Mutable)Collection<T>!
Set<T> Set<T> MutableSet<T> (Mutable)Set<T>!
List<T> List<T> MutableList<T> (Mutable)List<T>!
ListIterator<T> ListIterator<T> MutableListIterator<T> (Mutable)ListIterator<T>!
Map<K, V> Map<K, V> MutableMap<K, V> (Mutable)Map<K, V>!
Map.Entry<K, V> Map.Entry<K, V> MutableMap.MutableEntry<K,V> (Mutable)Map.(Mutable)Entry<K, V>!

{:.zebra}

Java 的數(shù)組按下文所述映射:

Java 類型 Kotlin 類型
int[] kotlin.IntArray!
String[] kotlin.Array<(out) String>!

{:.zebra}

Kotlin 中的 Java 泛型

Kotlin 的泛型與 Java 有點(diǎn)不同(參見泛型)。當(dāng)將 Java 類型導(dǎo)入 Kotlin 時,我們會執(zhí)行一些轉(zhuǎn)換:

  • Java 的通配符轉(zhuǎn)換成類型投影

    • Foo<? extends Bar> 轉(zhuǎn)換成 Foo<out Bar!>!
    • Foo<? super Bar> 轉(zhuǎn)換成 Foo<in Bar!>!
  • Java的原始類型轉(zhuǎn)換成星投影

    • List 轉(zhuǎn)換成 List<*>!,即 List<out Any?>!

和 Java 一樣,Kotlin 在運(yùn)行時不保留泛型,即對象不攜帶傳遞到他們構(gòu)造器中的那些類型參數(shù)的實際類型。
ArrayList<Integer>()ArrayList<Character>() 是不能區(qū)分的。
這使得執(zhí)行 is{: .keyword }-檢測不可能照顧到泛型。
Kotlin 只允許 is{: .keyword }-檢測星投影的泛型類型:

if (a is List<Int>) // 錯誤:無法檢查它是否真的是一個 Int 列表
// but
if (a is List<*>) // OK:不保證列表的內(nèi)容

Java 數(shù)組

與 Java 不同,Kotlin 中的數(shù)組是不型變的。這意味著 Kotlin 不允許我們把一個 Array<String> 賦值給一個 Array<Any>
從而避免了可能的運(yùn)行時故障。Kotlin 也禁止我們把一個子類的數(shù)組當(dāng)做超類的數(shù)組傳遞給 Kotlin 的方法,
但是對于 Java 方法,這是允許的(通過 Array<(out) String>! 這種形式的平臺類型)。

Java 平臺上,數(shù)組會使用原生數(shù)據(jù)類型以避免裝箱/拆箱操作的開銷。
由于 Kotlin 隱藏了這些實現(xiàn)細(xì)節(jié),因此需要一個變通方法來與 Java 代碼進(jìn)行交互。
對于每種原生類型的數(shù)組都有一個特化的類(IntArray、 DoubleArray、 CharArray 等等)來處理這種情況。
它們與 Array 類無關(guān),并且會編譯成 Java 原生類型數(shù)組以獲得最佳性能。

假設(shè)有一個接受 int 數(shù)組索引的 Java 方法:

public class JavaArrayExample {

    public void removeIndices(int[] indices) {
        // 在此編碼……
    }
}

在 Kotlin 中你可以這樣傳遞一個原生類型的數(shù)組:

val javaObj = JavaArrayExample()
val array = intArrayOf(0, 1, 2, 3)
javaObj.removeIndices(array)  // 將 int[] 傳給方法

當(dāng)編譯為 JVM 字節(jié)代碼時,編譯器會優(yōu)化對數(shù)組的訪問,這樣就不會引入任何開銷:

val array = arrayOf(1, 2, 3, 4)
array[x] = array[x] * 2 // 不會實際生成對 get() 和 set() 的調(diào)用
for (x in array) { // 不會創(chuàng)建迭代器
    print(x)
}

即使當(dāng)我們使用索引定位時,也不會引入任何開銷

for (i in array.indices) {// 不會創(chuàng)建迭代器
    array[i] += 2
}

最后,in{: .keyword }-檢測也沒有額外開銷

if (i in array.indices) { // 同 (i >= 0 && i < array.size)
    print(array[i])
}

Java 可變參數(shù)

Java 類有時聲明一個具有可變數(shù)量參數(shù)(varargs)的方法來使用索引。

public class JavaArrayExample {

    public void removeIndices(int... indices) {
        // 在此編碼……
    }
}

在這種情況下,你需要使用展開運(yùn)算符 * 來傳遞 IntArray

val javaObj = JavaArray()
val array = intArrayOf(0, 1, 2, 3)
javaObj.removeIndicesVarArg(*array)

目前無法傳遞 null{: .keyword } 給一個聲明為可變參數(shù)的方法。

操作符

由于 Java 無法標(biāo)記用于運(yùn)算符語法的方法,Kotlin 允許
具有正確名稱和簽名的任何 Java 方法作為運(yùn)算符重載和其他約定(invoke() 等)使用。
不允許使用中綴調(diào)用語法調(diào)用 Java 方法。

受檢異常

在 Kotlin 中,所有異常都是非受檢的,這意味著編譯器不會強(qiáng)迫你捕獲其中的任何一個。
因此,當(dāng)你調(diào)用一個聲明受檢異常的 Java 方法時,Kotlin 不會強(qiáng)迫你做任何事情:

fun render(list: List<*>, to: Appendable) {
    for (item in list) {
        to.append(item.toString()) // Java 會要求我們在這里捕獲 IOException
    }
}

對象方法

當(dāng) Java 類型導(dǎo)入到 Kotlin 中時,類型 java.lang.Object 的所有引用都成了 Any。
而因為 Any 不是平臺指定的,它只聲明了 toString()、hashCode()equals() 作為其成員,
所以為了能用到 java.lang.Object 的其他成員,Kotlin 要用到擴(kuò)展函數(shù)。

wait()/notify()

Effective Java 第 69 條善意地建議優(yōu)先使用并發(fā)工具(concurrency utilities)而不是 wait()notify()。
因此,類型 Any 的引用不提供這兩個方法。
如果你真的需要調(diào)用它們的話,你可以將其轉(zhuǎn)換為 java.lang.Object

(foo as java.lang.Object).wait()

getClass()

要取得對象的 Java 類,請在類引用上使用 java 擴(kuò)展屬性。

val fooClass = foo::class.java

上面的代碼使用了自 Kotlin 1.1 起支持的綁定的類引用。你也可以使用 javaClass 擴(kuò)展屬性。

val fooClass = foo.javaClass

clone()

要覆蓋 clone(),需要繼承 kotlin.Cloneable


class Example : Cloneable {
    override fun clone(): Any { …… }
}

不要忘記 Effective Java 的第 11 條: 謹(jǐn)慎地改寫clone。

finalize()

要覆蓋 finalize(),所有你需要做的就是簡單地聲明它,而不需要 override{:.keyword} 關(guān)鍵字:

class C {
    protected fun finalize() {
        // 終止化邏輯
    }
}

根據(jù) Java 的規(guī)則,finalize() 不能是 private{: .keyword } 的。

從 Java 類繼承

在 kotlin 中,類的超類中最多只能有一個 Java 類(以及按你所需的多個 Java 接口)。

訪問靜態(tài)成員

Java 類的靜態(tài)成員會形成該類的“伴生對象”。我們無法將這樣的“伴生對象”作為值來傳遞,
但可以顯式訪問其成員,例如:

if (Character.isLetter(a)) {
    // ……
}

Java 反射

Java 反射適用于 Kotlin 類,反之亦然。如上所述,你可以使用 instance::class.java,
ClassName::class.java 或者 instance.javaClass 通過 java.lang.Class 來進(jìn)入 Java 反射。

其他支持的情況包括為一個 Kotlin 屬性獲取一個 Java 的 getter/setter 方法或者幕后字段、為一個 Java 字段獲取一個 KProperty、為一個 KFunction 獲取一個 Java 方法或者構(gòu)造函數(shù),反之亦然。

SAM 轉(zhuǎn)換

就像 Java 8 一樣,Kotlin 支持 SAM 轉(zhuǎn)換。這意味著 Kotlin 函數(shù)字面值可以被自動的轉(zhuǎn)換成
只有一個非默認(rèn)方法的 Java 接口的實現(xiàn),只要這個方法的參數(shù)類型
能夠與這個 Kotlin 函數(shù)的參數(shù)類型相匹配。

你可以這樣創(chuàng)建 SAM 接口的實例:

val runnable = Runnable { println("This runs in a runnable") }

……以及在方法調(diào)用中:

val executor = ThreadPoolExecutor()
// Java 簽名:void execute(Runnable command)
executor.execute { println("This runs in a thread pool") }

如果 Java 類有多個接受函數(shù)式接口的方法,那么可以通過使用
將 lambda 表達(dá)式轉(zhuǎn)換為特定的 SAM 類型的適配器函數(shù)來選擇需要調(diào)用的方法。這些適配器函數(shù)也會按需
由編譯器生成。

executor.execute(Runnable { println("This runs in a thread pool") })

請注意,SAM 轉(zhuǎn)換只適用于接口,而不適用于抽象類,即使這些抽象類也只有一個
抽象方法。

還要注意,此功能只適用于 Java 互操作;因為 Kotlin 具有合適的函數(shù)類型,所以不需要將函數(shù)自動轉(zhuǎn)換
為 Kotlin 接口的實現(xiàn),因此不受支持。

在 Kotlin 中使用 JNI

要聲明一個在本地(C 或 C++)代碼中實現(xiàn)的函數(shù),你需要使用 external 修飾符來標(biāo)記它:

external fun foo(x: Int): Double

其余的過程與 Java 中的工作方式完全相同。