<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Java 中調用 Kotlin [TOC] Java 可以輕松調用 Kotlin 代碼。 例如,Kotlin 類的實例可以在 Java 方法中無縫創建和操作。但是,在將 Kotlin 代碼集成到 Java 中時,Java 和 Kotlin 之間存在某些差異。在此頁上,我們將介紹將 Kotlin 代碼與其 Java 客戶端的互操作定制的方法。 ## 屬性 Kotlin 屬性會編譯成以下 Java 元素: * 一個 getter 方法,名稱通過加前綴 `get` 算出; * 一個 setter 方法,名稱通過加前綴 `set` 算出(只適用于 `var` 屬性); * 一個私有字段,與屬性名稱相同(僅適用于具有幕后字段的屬性)。 例如,`var firstName: String` 編譯成以下 Java 聲明: ``` java private String firstName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } ``` 如果屬性的名稱以 `is` 開頭,則使用不同的名稱映射規則:getter 的名稱與屬性名稱相同,并且 setter 的名稱是通過將 `is` 替換為 `set` 獲得。 例如,對于屬性 `isOpen`,其 getter 會稱做 `isOpen()`,而其 setter 會稱做 `setOpen()`。這一規則適用于任何類型的屬性,并不僅限于 `Boolean`。 ## 包級函數 在 `org.example` 包內的 `app.kt` 文件中聲明的所有的函數和屬性,包括擴展函數,都編譯成一個名為 `org.example.AppKt` 的 Java 類的靜態方法 ```kotlin // app.kt package org.example class Util fun getTime() { /*……*/ } ``` ``` java // Java new org.example.Util(); org.example.AppKt.getTime(); ``` 可以使用 `@JvmName` 注解修改生成的 Java 類的類名: ```kotlin @file:JvmName("DemoUtils") package org.example class Util fun getTime() { /*……*/ } ``` ``` java // Java new org.example.Util(); org.example.DemoUtils.getTime(); ``` 如果多個文件中生成了相同的 Java 類名(包名相同并且類名相同或者有相同的[`@JvmName`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-name/index.html) 注解)通常是錯誤的。然而,編譯器能夠生成一個單一的 Java 外觀類,它具有指定的名稱且包含來自所有文件中具有該名稱的所有聲明。 要啟用生成這樣的外觀,請在所有相關文件中使用 [`@JvmMultifileClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-multifile-class/index.html) 注解。 ```kotlin // oldutils.kt @file:JvmName("Utils") @file:JvmMultifileClass package org.example fun getTime() { /*……*/ } ``` ```kotlin // newutils.kt @file:JvmName("Utils") @file:JvmMultifileClass package org.example fun getDate() { /*……*/ } ``` ``` java // Java org.example.Utils.getTime(); org.example.Utils.getDate(); ``` ## 實例字段 如果需要在 Java 中將 Kotlin 屬性作為字段暴露,那就使用 [`@JvmField`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-field/index.html) 注解對其標注。 該字段將具有與底層屬性相同的可見性。如果一個屬性有幕后字段(backing field)、非私有、沒有 `open`、`override` 或者 `const` 修飾符并且不是被委托的屬性,那么你可以用 `@JvmField` 注解該屬性。 ```kotlin class User(id: String) { @JvmField val ID = id } ``` ``` java // Java class JavaClient { public String getID(User user) { return user.ID; } } ``` [延遲初始化的](http://www.kotlincn.net/docs/reference/properties.html#%E5%BB%B6%E8%BF%9F%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B1%9E%E6%80%A7%E4%B8%8E%E5%8F%98%E9%87%8F)屬性(在Java中)也會暴露為字段。該字段的可見性與 `lateinit` 屬性的 setter 相同。 ## 靜態字段 在命名對象或伴生對象中聲明的 Kotlin 屬性會在該命名對象或包含伴生對象的類中具有靜態幕后字段。 通常這些字段是私有的,但可以通過以下方式之一暴露出來: - [`@JvmField`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-field/index.html) 注解; - `lateinit` 修飾符; - `const` 修飾符。 使用 `@JvmField` 標注這樣的屬性使其成為與屬性本身具有相同可見性的靜態字段。 ```kotlin class Key(val value: Int) { companion object { @JvmField val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value } } } ``` ``` java // Java Key.COMPARATOR.compare(key1, key2); // Key 類中的 public static final 字段 ``` 在命名對象或者伴生對象中的一個[延遲初始化的](http://www.kotlincn.net/docs/reference/properties.html#%E5%BB%B6%E8%BF%9F%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B1%9E%E6%80%A7%E4%B8%8E%E5%8F%98%E9%87%8F)屬性具有與屬性 setter 相同可見性的靜態幕后字段。 ```kotlin object Singleton { lateinit var provider: Provider } ``` ``` java // Java Singleton.provider = new Provider(); // 在 Singleton 類中的 public static 非-final 字段 ``` (在類中以及在頂層)以 `const` 聲明的屬性在 Java 中會成為靜態字段: ```kotlin // 文件 example.kt object Obj { const val CONST = 1 } class C { companion object { const val VERSION = 9 } } const val MAX = 239 ``` 在 Java 中: ``` java int const = Obj.CONST; int max = ExampleKt.MAX; int version = C.VERSION; ``` ## 靜態方法 如上所述,Kotlin 將包級函數表示為靜態方法。Kotlin 還可以為命名對象或伴生對象中定義的函數生成靜態方法,如果你將這些函數標注為 [`@JvmStatic`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-static/index.html) 的話。如果你使用該注解,編譯器既會在相應對象的類中生成靜態方法,也會在對象自身中生成實例方法。 例如: ```kotlin class C { companion object { @JvmStatic fun callStatic() {} fun callNonStatic() {} } } ``` 現在,`callStatic()` 在 Java 中是靜態的,而 `callNonStatic()` 不是: ``` java C.callStatic(); // 沒問題 C.callNonStatic(); // 錯誤:不是一個靜態方法 C.Companion.callStatic(); // 保留實例方法 C.Companion.callNonStatic(); // 唯一的工作方式 ``` 對于命名對象也同樣: ```kotlin object Obj { @JvmStatic fun callStatic() {} fun callNonStatic() {} } ``` 在 Java 中: ``` java Obj.callStatic(); // 沒問題 Obj.callNonStatic(); // 錯誤 Obj.INSTANCE.callNonStatic(); // 沒問題,通過單例實例調用 Obj.INSTANCE.callStatic(); // 也沒問題 ``` Starting from Kotlin 1.3, `@JvmStatic` applies to functions defined in companion objects of interfaces as well. Such functions compile to static methods in interfaces. Note that static method in interfaces were introduced in Java 1.8,so be sure to use the corresponding targets. ```kotlin interface ChatBot { companion object { @JvmStatic fun greet(username: String) { println("Hello, $username") } } } ``` `@JvmStatic` 注解也可以應用于對象或伴生對象的屬性,使其 getter 和 setter 方法在該對象或包含該伴生對象的類中是靜態成員。 ## Default methods in interfaces > Default methods are available only for targets JVM 1.8 and above. > The `@JvmDefault` annotation is experimental in Kotlin 1.3. Its name and behavior may change, leading to future incompatibility. Starting from JDK 1.8, interfaces in Java can contain [default methods](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html). You can declare a non-abstract member of a Kotlin interface as default for the Java classes implementing it. To make a member default, mark it with the [`@JvmDefault`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/index.html) annotation. Here is an example of a Kotlin interface with a default method: ```kotlin interface Robot { @JvmDefault fun move() { println("~walking~") } fun speak(): Unit } ``` The default implementation is available for Java classes implementing the interface. ```java //Java implementation public class C3PO implements Robot { // move() implementation from Robot is available implicitly @Override public void speak() { System.out.println("I beg your pardon, sir"); } } ``` ```java C3PO c3po = new C3PO(); c3po.move(); // default implementation from the Robot interface c3po.speak(); ``` Implementations of the interface can override default methods. ```java //Java public class BB8 implements Robot { //own implementation of the default method @Override public void move() { System.out.println("~rolling~"); } @Override public void speak() { System.out.println("Beep-beep"); } } ``` For the `@JvmDefault` annotation to take effect, the interface must be compiled with an `-Xjvm-default` argument. Depending on the case of adding the annotation, specify one of the argument values: * `-Xjvm-default=enabled` should be used if you add only new methods with the `@JvmDefault` annotation. This includes adding the entire interface for your API. * `-Xjvm-default=compatibility` should be used if you are adding a `@JvmDefault` to the methods that were available in the API before. This mode helps avoid compatibility breaks: all the interface implementations written for the previous versions will be fully compatible with the new version. However, the compatibility mode may add some overhead to the resulting bytecode size and affect the performance. For more details about compatibility issues, see the `@JvmDefault` [reference page](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/index.html). Note that if an interface with `@JvmDefault` methods is used as a [delegate](/docs/reference/delegation.html), the default method implementations are called even if the actual delegate type provides its own implementations. ```kotlin interface Producer { @JvmDefault fun produce() { println("interface method") } } class ProducerImpl: Producer { override fun produce() { println("class method") } } class DelegatedProducer(val p: Producer): Producer by p { } fun main() { val prod = ProducerImpl() DelegatedProducer(prod).produce() // prints "interface method" } ``` For more details about interface delegation in Kotlin, see [Delegation](/docs/reference/delegation.html). ## 可見性 Kotlin 的可見性以下列方式映射到 Java: * `private` 成員編譯成 `private` 成員; * `private` 的頂層聲明編譯成包級局部聲明; * `protected` 保持 `protected`(注意 Java 允許訪問同一個包中其他類的受保護成員, 而 Kotlin 不能,所以 Java 類會訪問更廣泛的代碼); * `internal` 聲明會成為 Java 中的 `public`。`internal` 類的成員會通過名字修飾,使其更難以在 Java 中意外使用到,并且根據 Kotlin 規則使其允許重載相同簽名的成員而互不可見; * `public` 保持 `public`。 ## KClass 有時你需要調用有 `KClass` 類型參數的 Kotlin 方法。因為沒有從 `Class` 到 `KClass` 的自動轉換,所以你必須通過調用`Class<T>.kotlin` 擴展屬性的等價形式來手動進行轉換: ```kotlin kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class) ``` ## 用 `@JvmName` 解決簽名沖突 有時我們想讓一個 Kotlin 中的命名函數在字節碼中有另外一個 JVM 名稱。最突出的例子是由于*類型擦除*引發的: ```kotlin fun List<String>.filterValid(): List<String> fun List<Int>.filterValid(): List<Int> ``` 這兩個函數不能同時定義,因為它們的 JVM 簽名是一樣的:`filterValid(Ljava/util/List;)Ljava/util/List;`。 如果我們真的希望它們在 Kotlin 中用相同名稱,我們需要用 [`@JvmName`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-name/index.html) 去標注其中的一個(或兩個),并指定不同的名稱作為參數: ```kotlin fun List<String>.filterValid(): List<String> @JvmName("filterValidInt") fun List<Int>.filterValid(): List<Int> ``` 在 Kotlin 中它們可以用相同的名稱 `filterValid` 來訪問,而在 Java 中,它們分別是 `filterValid` 和 `filterValidInt`。 同樣的技巧也適用于屬性 `x` 和函數 `getX()` 共存: ```kotlin val x: Int @JvmName("getX_prop") get() = 15 fun getX() = 10 ``` 如需在沒有顯式實現 getter 與 setter 的情況下更改屬性生成的訪問器方法的名稱,可以使用 `@get:JvmName` 與 `@set:JvmName`: ```kotlin @get:JvmName("x") @set:JvmName("changeX") var x: Int = 23 ``` ## 生成重載 通常,如果你寫一個有默認參數值的 Kotlin 函數,在 Java 中只會有一個所有參數都存在的完整參數簽名的方法可見,如果希望向 Java 調用者暴露多個重載,可以使用[`@JvmOverloads`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-overloads/index.html) 注解。 該注解也適用于構造函數、靜態方法等。它不能用于抽象方法,包括在接口中定義的方法。 ```kotlin class Circle @JvmOverloads constructor(centerX: Int, centerY: Int, radius: Double = 1.0) { @JvmOverloads fun draw(label: String, lineWidth: Int = 1, color: String = "red") { /*……*/ } } ``` 對于每一個有默認值的參數,都會生成一個額外的重載,這個重載會把這個參數和它右邊的所有參數都移除掉。在上例中,會生成以下代碼: ``` java // 構造函數: Circle(int centerX, int centerY, double radius) Circle(int centerX, int centerY) // 方法 void draw(String label, int lineWidth, String color) { } void draw(String label, int lineWidth) { } void draw(String label) { } ``` 請注意,如[次構造函數](http://www.kotlincn.net/docs/reference/classes.html#%E6%AC%A1%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0)中所述,如果一個類的所有構造函數參數都有默認值,那么會為其生成一個公有的無參構造函數。這就算沒有 `@JvmOverloads` 注解也有效。 ## 受檢異常 如上所述,Kotlin 沒有受檢異常。所以,通常 Kotlin 函數的 Java 簽名不會聲明拋出異常。于是如果我們有一個這樣的 Kotlin 函數: ```kotlin // example.kt package demo fun writeToFile() { /*……*/ throw IOException() } ``` 然后我們想要在 Java 中調用它并捕捉這個異常: ``` java // Java try { demo.Example.writeToFile(); } catch (IOException e) { // 錯誤:writeToFile() 未在 throws 列表中聲明 IOException // …… } ``` 因為 `writeToFile()` 沒有聲明 `IOException`,我們從 Java 編譯器得到了一個報錯消息。為了解決這個問題,要在 Kotlin 中使用 [`@Throws`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html) 注解。 ```kotlin @Throws(IOException::class) fun writeToFile() { /*……*/ throw IOException() } ``` ## 空安全性 當從 Java 中調用 Kotlin 函數時,沒人阻止我們將 *null* 作為非空參數傳遞。這就是為什么 Kotlin 給所有期望非空參數的公有函數生成運行時檢測。這樣我們就能在 Java 代碼里立即得到 `NullPointerException`。 ## 型變的泛型 當 Kotlin 的類使用了[聲明處型變](generics.html#聲明處型變),有兩種選擇可以從 Java 代碼中看到它們的用法。讓我們假設我們有以下類和兩個使用它的函數: ```kotlin 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 ``` 一種看似理所當然地將這倆函數轉換成 Java 代碼的方式可能會是: ``` java Box<Derived> boxDerived(Derived value) { …… } Base unboxBase(Box<Base> box) { …… } ``` 問題是,在 Kotlin 中我們可以這樣寫 `unboxBase(boxDerived("s"))`,但是在 Java 中是行不通的,因為在 Java 中類 `Box` 在其泛型參數 `T` 上是*不型變的*,于是 `Box<Derived>` 并不是 `Box<Base>` 的子類。要使其在 Java 中工作,我們按以下這樣定義 `unboxBase`: ``` java Base unboxBase(Box<? extends Base> box) { …… } ``` 這里我們使用 Java 的*通配符類型*(`? extends Base`)來通過使用處型變來模擬聲明處型變,因為在 Java 中只能這樣。 當它*作為參數*出現時,為了讓 Kotlin 的 API 在 Java 中工作,對于協變定義的 `Box` 我們生成 `Box<Super>` 作為 `Box<? extends Super>`(或者對于逆變定義的 `Foo` 生成 `Foo<? super Bar>`)。當它是一個返回值時,我們不生成通配符,因為否則 Java 客戶端將必須處理它們(并且它違反常用Java 編碼風格)。因此,我們的示例中的對應函數實際上翻譯如下: ``` java // 作為返回類型——沒有通配符 Box<Derived> boxDerived(Derived value) { …… } // 作為參數——有通配符 Base unboxBase(Box<? extends Base> box) { …… } ``` 當參數類型是 final 時,生成通配符通常沒有意義,所以無論在什么地方 `Box<String>`始終轉換為 `Box<String>`。 如果我們在默認不生成通配符的地方需要通配符,我們可以使用 `@JvmWildcard` 注解: ```kotlin fun boxDerived(value: Derived): Box<@JvmWildcard Derived> = Box(value) // 將被轉換成 // Box<? extends Derived> boxDerived(Derived value) { …… } ``` 另一方面,如果我們根本不需要默認的通配符轉換,我們可以使用`@JvmSuppressWildcards` ```kotlin fun unboxBase(box: Box<@JvmSuppressWildcards Base>): Base = box.value // 會翻譯成 // Base unboxBase(Box<Base> box) { …… } ``` `@JvmSuppressWildcards` 不僅可用于單個類型參數,還可用于整個聲明(如函數或類),從而抑制其中的所有通配符。 ### `Nothing` 類型翻譯 類型 [`Nothing`](exceptions.html#nothing-類型) 是特殊的,因為它在 Java 中沒有自然的對應。確實,每個 Java 引用類型,包括`java.lang.Void` 都可以接受 `null` 值,但是 Nothing 不行。因此,這種類型不能在 Java 世界中準確表示。這就是為什么在使用 `Nothing` 參數的地方 Kotlin 生成一個原始類型: ```kotlin fun emptyList(): List<Nothing> = listOf() // 會翻譯成 // List emptyList() { …… } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看