Kotlin与Java的互操作性

Google最近发布了Android Kotlin Guide,其中包括Kotlin和Java的interp guide,这篇文章主要介绍interp guide。

Java侧的注意事项

  • 不要使用kotlin的hard keywords作为方法名,这样会导致kotlin调用Java方法需要使用backticks
val callable = Mockito.mock(Callable::class.java)
Mockito.`when`(callable.call()).thenReturn(/* … */)
  • 符合SAM(single abstract method)规则的函数参数应该放到最后

  • 如果要让方法能够在kotlin中作为property调用,要使用bean style前缀(get, set)

//Java
public final class User {
  public String getName() { /* … */ }
  public void setName(String name) { /* … */ }
}
//Kotlin
user.name = "Bob" // Invokes user.setName(String)
  • 如果方法名符合kotlin中的operator overloading,要使功能与operator匹配
//Java
public final class IntBox {
  private final int value;
  public IntBox(int value) {
    this.value = value;
  }
  public IntBox plus(IntBox other) {
    return new IntBox(value + other.value);
  }
}

//Kotlin
val one = IntBox(1)
val two = IntBox(2)
val three = one + two // Invokes one.plus(two)
  • non-primitive的入参和出参都要用nullability notation标注,不然在kotlin中只能当成platform type而不能进行nullability检查

Kotlin侧注意事项

  • 当一个文件包含top-level函数和属性时,要用@file:JvmName("Foo")去更改生成类的名字,不然会生成**Kt的名称。

  • 使用@file:JvmMultifileClass将多个声明同名JvmName的的属性和方法合并到一个类里。

  • 不用使用Nothing作为generic type

  • 抛出checked exception的函数需要在文档里用@Throw标出。

  • 当返回shared或者read-only collections时, 要包装在immutable collection中或者做defensive copy

  • Companion Object中function要用@JvmStatic修饰

Incorrect: no annotation

class KotlinClass {
    companion object {
        fun doWork() {
            /* … */
        }
    }
}
public final class JavaClass {
    public static void main(String... args) {
        KotlinClass.Companion.doWork();
    }
}

Correct: @JvmStatic annotation

class KotlinClass {
    companion object {
        @JvmStatic fun doWork() {
            /* … */
        }
    }
}
public final class JavaClass {
    public static void main(String... args) {
        KotlinClass.doWork();
    }
}
  • Companion object或者单例object中没有用const修饰的val变量,只能通过getter访问。

使用@JVMField修饰后,可以直接作为静态变量使用

Incorrect: no annotation

class KotlinClass {
    companion object {
        const val INTEGER_ONE = 1
        val BIG_INTEGER_ONE = BigInteger.ONE
    }
}
public final class JavaClass {
    public static void main(String... args) {
        System.out.println(KotlinClass.INTEGER_ONE);
        System.out.println(KotlinClass.Companion.getBIG_INTEGER_ONE());
    }
}

Incorrect: @JvmStatic annotation

class KotlinClass {
    companion object {
        const val INTEGER_ONE = 1
        @JvmStatic val BIG_INTEGER_ONE = BigInteger.ONE
    }
}
public final class JavaClass {
    public static void main(String... args) {
        System.out.println(KotlinClass.INTEGER_ONE);
        System.out.println(KotlinClass.getBIG_INTEGER_ONE());
    }
}

Correct: @JvmField annotation

class KotlinClass {
    companion object {
        const val INTEGER_ONE = 1
        @JvmField val BIG_INTEGER_ONE = BigInteger.ONE
    }
}
public final class JavaClass {
    public static void main(String... args) {
        System.out.println(KotlinClass.INTEGER_ONE);
        System.out.println(KotlinClass.BIG_INTEGER_ONE;
    }
}

因为extension function在Java中会转变为静态函数,所以要用@JvmName转换成idiomatic的命名

sealed class Optional
data class Some(val value: T): Optional()
object None : Optional()

@JvmName("ofNullable")
fun  T?.asOptional() = if (this == null) None else Some(this)
// FROM KOTLIN:
fun main(vararg args: String) {
    val nullableString: String? = "foo"
    val optionalString = nullableString.asOptional()
}
// FROM JAVA:
public static void main(String... args) {
    String nullableString = "Foo";
    Optional optionalString =
          Optionals.ofNullable(nullableString);
}
  • 具有default value参数的函数需要使用@JvmOverloads

Incorrect: No @JvmOverloads

class Greeting {
    fun sayHello(prefix: String = "Mr.", name: String) {
        println("Hello, $prefix $name")
    }
}
public class JavaClass {
    public static void main(String... args) {
        Greeting greeting = new Greeting();
        greeting.sayHello("Mr.", "Bob");
    }
}

Correct: @JvmOverloads annotation.

class Greeting {
    @JvmOverloads
    fun sayHello(prefix: String = "Mr.", name: String) {
        println("Hello, $prefix $name")
    }
}
public class JavaClass {
    public static void main(String... args) {
        Greeting greeting = new Greeting();
        greeting.sayHello("Bob");
    }
}

你可能感兴趣的:(Kotlin与Java的互操作性)