《Kotlin 程序設計》第九章 Kotlin與Java混合調(diào)用

第九章 Kotlin與Java混合調(diào)用

雖然 Kotlin 的開發(fā)很方便,但當你與他人協(xié)作時,總會碰到 Java 與 Kotlin 代碼共存的代碼項目。本章就教你如何優(yōu)雅的實現(xiàn) Kotlin 與 Java 混合編程。

1 使用工具互相轉(zhuǎn)換

1.1 將 Java 轉(zhuǎn)換為 Kotlin

如果你之前使用 Java 語言而沒有 Kotlin 開發(fā)經(jīng)驗,不用擔心,Intellij IDEA 會幫你一鍵轉(zhuǎn)換,將 Java 代碼轉(zhuǎn)換成 Kotlin 代碼。

1.2 將 Kotlin 轉(zhuǎn)換為 Java

另外,通過IDEA的Kotlin插件,可以直接把Kotlin代碼ByteCode反編譯成Java代碼(雖然這個反編譯后的Java代碼不是那么的的原汁原味)。

2 反射獲取類的 Class

在 Java 或 Android 開發(fā)中,經(jīng)常會直接調(diào)用一個類的 Class 文件。我們在Java中是直接這么調(diào)用的 Xyz.class。

這樣的方式,在Kotlin中稍微有點不同。在 M13 之前, Kotlin 代碼使用JavaClass<Xyz>,而 M13 之后寫法為 Xyz::class.java 。

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

3.1 void 與 Unit

如果一個 Java 方法返回 void,對應的在 Kotlin 代碼中它將返回 Unit。在 Kotlin 中可以省略這個Unit返回類型。

3.2 Java 與 Kotlin 關(guān)鍵字沖突的處理

Java 有 static 關(guān)鍵字,在 Kotlin 中沒有這個關(guān)鍵字,你需要使用@JvmStatic
替代這個關(guān)鍵字。

同樣,在 Kotlin 中也有很多的關(guān)鍵字是 Java 中是沒有的。例如

in
is
data

等。

如果 Java 中使用了這些關(guān)鍵字,需要加上反引號轉(zhuǎn)義來避免沖突。例如

// Java 代碼中有個方法叫 is()
public void is(){
 //...
}
// 轉(zhuǎn)換為 Kotlin 代碼需要加反引號轉(zhuǎn)義
fun `is`() {
 //...
}

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

4.1 static 方法

上文已經(jīng)提到過,在 Kotlin 中沒有 static
關(guān)鍵字,那么如果在 Java 代碼中想要通過類名調(diào)用一個 Kotlin 類的方法,你需要給這個方法加入@JvmStatic注解。

另外,你也可以通過對象object調(diào)用這個方法。

代碼示例

StringUtils.isEmpty("hello");  
StringUtils.INSTANCE.isEmpty2("hello");

object StringUtils {
    @JvmStatic fun isEmpty(str: String): Boolean {
        return "" == str
    }

    fun isEmpty2(str: String): Boolean {
        return "" == str
    }
}

4.2 靜態(tài)方法與伴生對象companion object

class StringUtils {
    companion object {
       fun isEmpty(str: String): Boolean {
            return "" == str
        }
    }
}

companion object, 表示外部類的一個伴生對象,你可以把他理解為外部類自動創(chuàng)建了一個對象作為自己的field。與上面的類似,Java 在調(diào)用時,可以這樣寫:

StringUtils.Companion.isEmpty();

4.3 包級別函數(shù)

與 Java 不同,Kotlin 允許函數(shù)獨立存在,而不必依賴于某個類,這類函數(shù)我們稱之為包級別函數(shù)(Package-Level Functions)。

為了兼容 Java,Kotlin 默認會將所有的包級別函數(shù)放在當前kt源文件的類中。比如說,HelloWorld.kt中的包級別的函數(shù),默認會放到HelloWorldKt類中。

//@file:JvmName("MyExample")
package com.easy.kotlin

/**
 * Created by jack on 2017/5/29.
 */

import java.util.Date
import java.text.SimpleDateFormat

fun main(args: Array<String>) {
    println("Hello, world!")
    println(SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date()))
    println(helloKotlin())
}


fun helloKotlin():String {
    val words = mutableListOf<String>()
    words.add("Hello")
    words.add("Kotlin!")
    words.add(java.util.Date().toString())
    return words.joinToString(separator=" ")
}

反編譯看下Kotlin ByteCode:

// ================com/easy/kotlin/HelloWorldKt.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/easy/kotlin/HelloWorldKt {


  // access flags 0x19
  public final static main([Ljava/lang/String;)V
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
    LDC "Hello, world!"
    INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
    NEW java/text/SimpleDateFormat
    DUP
    LDC "yyyy-MM-dd HH:mm:ss"
    INVOKESPECIAL java/text/SimpleDateFormat.<init> (Ljava/lang/String;)V
    NEW java/util/Date
    DUP
    INVOKESPECIAL java/util/Date.<init> ()V
    INVOKEVIRTUAL java/text/SimpleDateFormat.format (Ljava/util/Date;)Ljava/lang/String;
    INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
    INVOKESTATIC com/easy/kotlin/HelloWorldKt.helloKotlin ()Ljava/lang/String;
    INVOKESTATIC kotlin/io/ConsoleKt.println (Ljava/lang/Object;)V
    RETURN
   L0
    MAXSTACK = 3
    MAXLOCALS = 1

  // access flags 0x19
  public final static helloKotlin()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
    INVOKESTATIC kotlin/collections/CollectionsKt.mutableListOf ()Ljava/util/List;
    ASTORE 0
   L0
    ALOAD 0
    LDC "Hello"
    INVOKEINTERFACE java/util/List.add (Ljava/lang/Object;)Z
    POP
    ALOAD 0
    LDC "Kotlin!"
    INVOKEINTERFACE java/util/List.add (Ljava/lang/Object;)Z
    POP
    ALOAD 0
    NEW java/util/Date
    DUP
    INVOKESPECIAL java/util/Date.<init> ()V
    INVOKEVIRTUAL java/util/Date.toString ()Ljava/lang/String;
    INVOKEINTERFACE java/util/List.add (Ljava/lang/Object;)Z
    POP
    ALOAD 0
    CHECKCAST java/lang/Iterable
    LDC " "
    CHECKCAST java/lang/CharSequence
    ACONST_NULL
    ACONST_NULL
    ICONST_0
    ACONST_NULL
    ACONST_NULL
    BIPUSH 62
    ACONST_NULL
    INVOKESTATIC kotlin/collections/CollectionsKt.joinToString$default (Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
    ARETURN
   L1
   L2
    LOCALVARIABLE words Ljava/util/List; L0 L2 0
    MAXSTACK = 9
    MAXLOCALS = 1

  // access flags 0x19
  public final static <clinit>()V
    RETURN
   L0
    MAXSTACK = 0
    MAXLOCALS = 0
}



我們可以看出,Kotlin中的包級別函數(shù)

fun helloKotlin()

被編譯成成了public final static 方法:

public final static helloKotlin()

在 Java 中想要調(diào)用包級別函數(shù)時,需要通過這個public final class com/easy/kotlin/HelloWorldKt類來調(diào)用。

我們也可以通過注解@file:JvmName("MyExample")來自定義這個類名。這樣當前文件中的所有包級別函數(shù), 將被放到一個自動生成的文件名為 MyExample 的類中。

代碼示例如下:

@file:JvmName("MyExample")
package com.easy.kotlin

/**
 * Created by jack on 2017/5/29.
 */

import java.util.Date
import java.text.SimpleDateFormat

fun main(args: Array<String>) {
    println("Hello, world!")
    println(SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date()))
    println(helloKotlin())
}


fun helloKotlin():String {
    val words = mutableListOf<String>()
    words.add("Hello")
    words.add("Kotlin!")
    words.add(java.util.Date().toString())
    return words.joinToString(separator=" ")
}

添加了如下代碼

@file:JvmName("MyExample")
package com.easy.kotlin

反編譯后:

// ================com/easy/kotlin/MyExample.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/easy/kotlin/MyExample {


  // access flags 0x19
  public final static main([Ljava/lang/String;)V
    ....

  // access flags 0x19
  public final static helloKotlin()Ljava/lang/String;
  ....
}



我們可以看到:類名變成了MyExample。

簡潔,使用更少的代碼做更多的事
在我看來,Kotlin很關(guān)鍵的一個優(yōu)點就是簡潔。相對于Java,使用Kotlin往往能夠用更少的代碼獲得更多的功能。這有什么好處呢?很簡單,寫的代碼越少,邏輯越清晰,所犯的錯誤就會越少。

  1. 數(shù)據(jù)類
    數(shù)據(jù)類大量重復的getter和setter相信會是很多人在開發(fā)過程中吐槽的一個點。舉一個很經(jīng)典的例子,我們需要一個Person的數(shù)據(jù)類。

在Java中,需要這么寫:

public class Person {
private String name;
private int age;
private int sex;
private float height;

public Person(String name, int age, int sex, float height) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.height = height;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public int getSex() {
     return sex;
}

public void setSex(int sex) {
    this.sex = sex;
}

public float getHeight() {
    return height;
}

public void setHeight(float height) {
    this.height = height;
}

@Override
public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", sex=" + (sex == 0 ? "男" : "女") +
            ", height=" + height +
            '}';

}
在Kotlin里,我們只需要一行代碼就能完成以上的功能:

data class Person(var name: String,
var age: Int,
var sex: Int,
var height: Float)
Kotlin提供的數(shù)據(jù)類會讓你自動獲得所需的getter、setters、toString(),這很大程度上減少了大量重復的工作。當然,我們也可以很輕松的去覆蓋這些函數(shù),做自定義的事情,但是在大多數(shù)情況下,只需聲明類和屬性就已經(jīng)足夠了。

  1. 區(qū)間表達式
    在Java中我們經(jīng)常要寫這樣的代碼,

for(int i = 0; i <= 10; i++){
System.out.println(i)
}
但是在Kotlin中,支持 .. 操作符形式的區(qū)間表達式,我們轉(zhuǎn)換成Kotlin就變成了這樣:

for(i in 0..10){
println(i)
}
是不是簡潔優(yōu)雅很多,不僅如此,還有更多相關(guān)的功能。

//倒序迭代
for(i in 10 downTo 0){
...
}

//步長為2的迭代
for(i in 0..10 setp 2){
...
}

//i在[0,10)區(qū)間,排除了10
for(i in 0 until 10){
...
}

  1. Lamda表達式
    Java在Java8才支持Lamda語法,在Kotlin里完全支持。有對比才有差距,看例子:

Java中:

btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//dosomething
}});
Kotlin中:

btn.setOnClickListener { //dosomething }

  1. 類擴展
    類擴展是一個超級強大的功能,我終于可以擺脫大量的Util工具類了。:)

看一個例子:

fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' 對應該列表
this[index1] = this[index2]
this[index2] = tmp
}
}

//使用
val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'swap()' 內(nèi)部的 'this' 得到 'l' 的值
是不是功能強大且代碼簡潔優(yōu)雅?當然,擴展并不能真正的修改它所擴展的類。通過定義一個擴展,我們并沒有在一個類中插入新的方法,僅僅是可以通過該類型的變量用點表達式來調(diào)用這個新函數(shù)。 口說無憑,我們來看看Kotlin編譯后的字節(jié)碼:

定義:

public final class ExtensionKt {
// access flags 0x19
// signature (Ljava/util/List<Ljava/lang/Integer;>;II)V
// declaration: void swap(java.util.List<java.lang.Integer>, int, int)
public final static swap(Ljava/util/List;II)V
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "receiver" INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V L1 LINENUMBER 6 L1 ALOAD 0 ILOAD 1 INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object; CHECKCAST java/lang/Number INVOKEVIRTUAL java/lang/Number.intValue ()I ISTORE 3 L2 LINENUMBER 7 L2 ALOAD 0 ILOAD 1 ALOAD 0 ILOAD 2 INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object; INVOKEINTERFACE java/util/List.set (ILjava/lang/Object;)Ljava/lang/Object; POP L3 LINENUMBER 8 L3 ALOAD 0 ILOAD 2 ILOAD 3 INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; INVOKEINTERFACE java/util/List.set (ILjava/lang/Object;)Ljava/lang/Object; POP L4 LINENUMBER 9 L4 RETURN L5 LOCALVARIABLE tmp I L2 L5 3 LOCALVARIABLEreceiver Ljava/util/List; L0 L5 0
LOCALVARIABLE index1 I L0 L5 1
LOCALVARIABLE index2 I L0 L5 2
MAXSTACK = 4
MAXLOCALS = 4

// compiled from: extension.kt
}

使用:

L1
LINENUMBER 11 L1
ALOAD 1
ICONST_0
ICONST_2
INVOKESTATIC ExtensionKt.swap (Ljava/util/List;II)V
L2
可以看出,Kotlin在編譯時會以所在文件名extension創(chuàng)建靜態(tài)類ExtensionKt,并將定義的擴展方法swap編譯成靜態(tài)方法供外部調(diào)用。

在Java中形式大致是這樣:

public final class ExtensionKt {
public static final void swap(@NotNull List list, int index1, int index2) {
int tmp = ((Number)list.get(index1)).intValue();
list.set(index1, receiver.get(index2));
list.set(index2, Integer.valueOf(tmp));
}
}
所以在底層,其實就是我們平時所寫的Util工具類,但是Kotlin默認幫我們實現(xiàn)了,我們只需更簡潔的編寫調(diào)用就好了。

安全,避免NPE空指針異常

  1. 空安全
    這是一個讓人又愛又恨的特性。一直以來,NullPointException空指針異常在開發(fā)中是最低級也最致命的問題。我們往往需要進行各種null的判斷以試圖去避免NPE的發(fā)生。Kotlin基于這個問題,提出了一個空安全的概念,即每個屬性默認不可為null。

舉個例子。

var a: String = "abcd"
a = null //編譯錯誤
如果要允許為空,我們需要手動聲明一個變量為可空字符串類型,寫為String?

var a: String? = "abcd"
a = null //編譯成功
那怎么實現(xiàn)默認不可為Null呢? 我們來看一下字節(jié)碼:

@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 10 L0
GETSTATIC PersonKt.a : Ljava/lang/String;
ARETURN
L1

//init
static <clinit>()V
L0
LINENUMBER 10 L0
LDC "abcd"
PUTSTATIC PersonKt.a : Ljava/lang/String;
RETURN
MAXSTACK = 1
MAXLOCALS = 0
可以看到Kotlin對變量進行了NotNull注解。翻譯成Java代碼:

@NotNull
String a = "abcd"
不僅如此,為了避免NPE異常,Kotlin做了一件很有趣的事:當你允許屬性可空時,Kotlin編譯器將不允許你在未經(jīng)檢查的情況下引用它。

var person: Person? = null
person.name = "shinelw" //編譯失敗
person?.name = "shinelw" //編譯成功
如上面的代碼所示,當person對象可為null時,必須強制使用 ?. 來進行null檢查??纯??. 在字節(jié)碼里的樣子,

LINENUMBER 13 L1
ALOAD 0
DUP
IFNULL L2
LDC "shinelw"
INVOKEVIRTUAL Person.setName (Ljava/lang/String;)V
GOTO L3

L2
POP
L3
可見,在person獲取name屬性的時候進行了null的判斷,翻譯成java代碼:

Person person = (Person)null;
if(person != null) {
person.setName("shinelw");
}
這么看來,空安全特性的確帶來了巨大的好處,極大程度上避免了空指針異常的出現(xiàn)。然而,世上沒有十全十美的東西??瞻踩陂_發(fā)過程中給我?guī)砹撕芏嘈腋5臒馈Ee個例子,以前用Java是這樣的:

public class A {
String a;
String b;
String c;
}
現(xiàn)在呢,Kotlin中是這樣的:

class A {
var a: String? = null
var b: String? = null
var c: String? = null
}
看出區(qū)別了嗎?

在Kotlin中我們需要在定義變量是就必須給出初始值。開發(fā)過程中,很多情況下變量在定義時尚不知道要賦何值的,Kotlin強制初始化賦值讓整個代碼看起來很“怪異”。對我來說,如果一個變量可為null時,它應該是隱含地就默認給予了null值。

我希望應該是這樣的,

class A {
var a: String? //默認值為null
var b: String? //默認值為null
var c: String? //默認值為null
}
雖然說Kotlin提供了lateinit類型懶加載的方式進行初始化,但是也并不能很好的支持全部情況,它只能用于var的屬性,并且只能在屬性沒有自定義getter或者setter時候使用。屬性的類型必須是非空值,并且它不能使原始類型。

當然,我們換個角度,從語言設計的角度來說,Kotlin這么設計又是很合理的。所有屬性要求強制顯式的初始化能夠更容易的推理代碼,明確每個屬性在何時何地初始化。

總的來說,空安全機制所做的事情就是,讓我們原本在邏輯代碼中進行大量判空的工作轉(zhuǎn)移到了初始化上,并很大程度地減輕了工作量。

更優(yōu)雅,遵循Effective Java設計

  1. 類默認不可繼承
    《Effective Java》提出一種觀點:組合優(yōu)于繼承,避免濫用繼承。要么為繼承而設計,并提供文檔說明,要么就禁止繼承。至于為什么這么說呢,我見過一句話很形象:攤開來的代碼,比疊起來的代碼,更加一目了然。詳細可以自行閱讀《Effective Java》。

Kotlin默認類是final類型的,即每個類默認不可繼承。只有你真的需要繼承的時候,再通過open聲明使用,聲明方式如下:

open class A

  1. 更有效地使用構(gòu)建器模式
    我們建議使用構(gòu)建器模式,當Java的構(gòu)造器存在多個可選的參數(shù)時,情況就會變得很復雜,代碼冗長,也更容易出錯。Kotlin提供了一種更有效的構(gòu)造器方式,通過默認參數(shù)的功能實現(xiàn)。

data class Person(var name: String,
var age: Int = 18,
var sex: Int = 0,
var height: Float = 1.8f
var weight: Float = 60f)

//創(chuàng)建對象
val person: Person = Person(name="shinelw",
age = 10,
height = 1.7f)

  1. 單例模式
    Kotlin默認提供了單例模式的模板,通過object關(guān)鍵字即可實現(xiàn)。

object Singleton {
//各種函數(shù)
fun a(){...}
...
}

//使用時
Singleton.a()
完全不需要手動構(gòu)建,看上去很好。但是我有一點質(zhì)疑,它是不是線程安全的,是不是懶加載的。隨后通過Kotlin編譯器得到字節(jié)碼,然后再反編譯回Java代碼。是長這樣子的:

public class Singleton {
public static final Singleton INSTANCE;

public final void a() {
}

private Singleton() {
INSTANCE = (Singleton)this;
}

static {
new Singleton();
}
}
糟糕的是,從上面代碼可以看出,Kotlin的object只是一個最簡單的餓漢式的單例模式。在第一次加載類到內(nèi)存的時候就會初始化,雖然它是線程安全的,但是不完美,對嗎?

如果你是一個追求完美的人,下面是類似于靜態(tài)內(nèi)部類方式實現(xiàn)的單例模式,懶加載且線程安全。缺點是跟Java一樣,需要手動構(gòu)建。:)

class Singleton private constructor(){
companion object {
fun getInstance(): Singleton {
return SingletonHolder.instance
}
}
private object SingletonHolder {
val instance: Singleton = Singleton()
}

//各種函數(shù)..
fun a(){}

}

  1. 重載必須使用override
    Java中對于重載的注解@Override不是強制的,一旦項目代碼很復雜,這將是一場災難。當你分不清哪些是重載方法時,對方法進行參數(shù)修改是災難性的。Kotlin基于這點,要求重載方法時必須加上override關(guān)鍵字。如果沒寫,編譯器將會報錯,強制你加上。

override fun a(){...}
完全兼容,與Java互操作
這是Kotlin與Scala相比,優(yōu)勢突出的一點。我們可以在Kotlin中調(diào)用現(xiàn)存的Java代碼,并且也能在Java代碼中順利的調(diào)用Kotlin代碼。這意味著我們可以馬上在現(xiàn)有的Java項目中使用上Kotlin,同時所有之前舊的Java也一樣有效。

這是很關(guān)鍵,也是我之所以很看好Kotlin的一個原因。

至于怎么相互調(diào)用操作,請大家看官方文檔關(guān)于Java互操作的部分。

這里只說一個方面,關(guān)于空安全方面。

因為Java中的任何應用都可以為null,但是在Kotlin中是默認不可為null的,這使得Kotlin對來自Java的對象要求嚴格空安全是不現(xiàn)實的。Java聲明的類型在Kotlin中會被特別對待,稱之為平臺類型。對這種類型的空檢查會放寬,因此他們的安全保證與Java中是相同的。

看下面的例子:

public class Person{
public String getName(){
return null;
}
}
val person = Person()
val name = person.name // 編譯通過 運行值為null
name本是非null變量,因為調(diào)用Java對象所以變成平臺類型,放寬了類型空檢查。

當然,如果你想要延續(xù)Kotlin嚴格空安全機制的話,可是有辦法滴。我們需要在編寫Java代碼時加上@NotNull注解,這個很熟悉吧,在介紹空安全機制的時候說過Kotlin在實現(xiàn)默認非null屬性就是這么實現(xiàn)的。然后代碼就變成了這樣,

public class Person{
public @NotNull String getName(){
return null;
}
}
然后在運行的時候就會報以下的錯誤:

Exception in thread "main" java.lang.IllegalStateException: @NotNull method Person.getName must not return null
at Person.$$$reportNull$$$0(Person.java)
at Person.getName(Person.java:9)
at MainKt.main(main.kt:7)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
總結(jié)
總而言之,經(jīng)過短短一個月的Kotlin使用,在實際項目中開發(fā)展現(xiàn)出的特性應用是讓我感到興奮的。作為一名開發(fā)者,在我眼里,Kotlin設計出來不是拋開Java談的,而是在Java的毛病的基礎上,進行的再開發(fā),擁有很多其他語言優(yōu)秀的特性,同時完全兼容Java。畢竟,對于一家大企業(yè)來講,為了一門新語言完全摒棄一個很成熟的項目進行再開發(fā)是不現(xiàn)實的。相反的是,對于項目中Java難于處理的邏輯,Kotlin的優(yōu)勢一覽無余,相輔相成,Kotlin和Java配合使用時目前最完美的方案。

但不可否認的是,Kotlin真的讓人感到潛力十足,值得大家去試一試。

參考資料:

1.http://kotlinlang.org/docs/reference/java-interop.html


Kotlin 開發(fā)者社區(qū)

國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號,主要分享、交流 Kotlin 編程語言、Spring Boot、Android、React.js/Node.js、函數(shù)式編程、編程思想等相關(guān)主題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 人生苦多,快來 Kotlin ,快速學習Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,761評論 9 118
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,699評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,853評論 18 399
  • Kotlin is 100% interoperable with Java? and Android? 在前面的...
    JackChen1024閱讀 6,615評論 1 15
  • 秋窗枯蝶非戀花,路間閑人無顧暇。白露凝霜節(jié)節(jié)寒,枝上紅柿謝春華。
    剪卻西風不問愁閱讀 190評論 0 0

友情鏈接更多精彩內(nèi)容