@946898963
2020-07-09T08:17:06.000000Z
字数 7189
阅读 1106
Kotlin
a. 当Java中的方法/字段的名称是Kotlin中的关键字时(如: in is object等), 我们可以通过使用反引号`来转义这个关键字
foo.`is`(bar)
b. Java 中的 int 和 Integer 只会对应 Kotlin 中 Int 这一种数据类型
Java 中的 int[] 会对应 Kotlin 中的 IntArray
Java 中的 Integer[] 会对应 Kotlin 中的 Array
其他的基本类型数组定义也是和上面一样的规则
// Javapublic void method(int[] intArray) {}// Kotlinmethod(IntArray(10))
c. Kotlin 调用 Java 中的变长参数的方法时, 可以使用 * 来传递/扩展数组
// Javapublic void method(int... params) {}// Kotlinval intArray = IntArray(10)method(*intArray) // 传递数组method(*intArray, 1, 2, 3) // 扩展数组
d. SAM接口的转换
总结: Kotlin中只有调用以Java中定义的SAM接口为参数的方法(不论是Java中还是Kotlin 中定义的)时, 编译器才会SAM转换, 从而我们才可以使用Lambda来传入方法, 否则都要实现 匿名内部类来传入方法
// Javapublic interface InterfaceJAVA {void print(String text);}public void printJavaFromJava(InterfaceJAVA interfaceJAVA) {interfaceJAVA.print("printJavaFromJava");}public void printKotlinFromJava(InterfaceKotlin interfaceKotlin) {interfaceKotlin.print("printKotlinFromJava");}// Kotlininterface InterfaceKotlin {fun print(text: String)}fun printJavaFromKotlin(interfaceJava: InterfaceJAVA) {interfaceJava.print("printJavaFromKotlin")}fun printKotlinFromKotlin(interfaceKotlin: InterfaceKotlin) {interfaceKotlin.print("printKotlinFromKotlin")}// 调用Java中定义的以Java中定义的SAM接口为参数的方法printJavaFromJava { println(it) }// 调用Java中定义的以Kotlin中定义的SAM接口为参数的方法printKotlinFromJava(object : InterfaceKotlin {override fun print(text: String) {println(text)}})// 调用Kotlin中定义的以Java中定义的SAM接口为参数的方法printJavaFromKotlin(InterfaceJAVA { println(it) })// 调用Kotlin中定义的以Kotlin中定义的SAM接口为参数的方法printKotlinFromKotlin(object : InterfaceKotlin {override fun print(text: String) {println(text)}
e. Kotlin中所有的异常都是非受检异常, 所以当我们在Kotlin中调用一个Java中的方法时, 需要自己判断是否需要try catch
Kotlin认为Java中的受检异常机制在大型项目中并不能够很好的增加项目的质量, 而且还会降低代码的可读性和复用性, 也会增加开发成本, 所以就把受检异常这个机制给去除了....
// Javapublic void methodWithException(int i) throws IOException {System.out.println("methodWithException start");if (i == 1) {throw new IOException();}System.out.println("methodWithException end");}// Java中调用methodWithException方法时, 必须强制处理IOException这个异常,// 因为IOException是一个受检异常try {methodWithException(0);} catch (IOException e) {e.printStackTrace();}// Kotlin// Kotlin中所有异常都不需要强制处理, 因此我们不需要强制的在调用methodWithException// 的地方去强制的try catch IOException异常methodWithException(0)
a. Java中调用Kotlin中定义的top-level declarations(顶级的类/方法/变量/常量等)时, 默认使用[Kotlin文件名]KT.[declarations name]的方式调用, 也可以在KT文件中使用JvmName注解来重新定义顶层变量的文件名
// Test.Ktpackage org.examplefun getTime() { /*...*/ }// Javaorg.example.TestKt.getTime();// Test.Kt@file:JvmName("DemoUtils")package org.examplefun getTime() { /*...*/ }// Javaorg.example.DemoUtils.getTime();
b. 如果想把多个KT文件中的top-level declarations合并, 可以使用JvmMultifileClass注解来合并多个Kt文件
// oldutils.kt@file:JvmName("Utils")@file:JvmMultifileClasspackage org.examplefun getTime() { /*...*/ }// newutils.kt@file:JvmName("Utils")@file:JvmMultifileClasspackage org.examplefun getDate() { /*...*/ }// Javaorg.example.Utils.getTime();org.example.Utils.getDate();
c. Java调用Kotlin的属性时如果不想通过getter/setter调用, 而是使用[objectName].[field]的方式调用, 则可以使用JvmField注解
前提是这个字段 1. 不是Private 2. 没有open override const修饰符 3. 不是委托属性
// Kotlinclass Person {@JvmField var name: String = "石硕"var height: Int = 190lateinit var brother: Person}// JavaPerson person = new Person();person.name = "猜猜我是谁" // 加了@JvmField注解后就可以直接操作fieldperson.setHeight(170) // 正常情况下只能使用setter/getter来操作fieldperson.brother = new Person() // 使用lateinit修饰的field也可以在Java中直接操作
d. Kotlin中的静态属性需要定义在companion object / 自定义的object中.
Java中调用Kotlin声明的静态属性时, 默认使用如下的两种方式:
如果想使用[ClassName].[fieldName] / [ObjectName].[fieldName] 的方式调用Kotlin中定 义的静态变量, 可以使用如下的三种方式:
// Kotlinclass TestStaticField {companion object {const val TEXT = "Text."@JvmFieldval TEXT_WITH_JVM_FIELD = "Text with JvmField"lateinit var TEXT_WITH_LATE_INIT: Stringval TEXT_NORMAL = "Text normal"}}// Java// 调用Const修饰静态属性System.out.println(TestStaticField.TEXT);// 调用@JvmField修饰的静态属性System.out.println(TestStaticField.TEXT_WITH_JVM_FIELD);// 调用latainit修饰的静态属性TestStaticField.TEXT_WITH_LATE_INIT = "Text with lateinit";// 默认的方式使用静态属性System.out.println(TestStaticField.Companion.getTEXT_NORMAL());
e. Kotlin中的静态方法与静态属性一样需要定义在companion object / 自定义的object中.
Java中调用Kotlin声明的静态方法时, 默认使用如下的两种方式:
如果想使用[ClassName].[methodName] / [ObjectName].[methodName] 的方式调用Kotlin中定义的静态方法, 可以使用@JvmStatic注解
// Kotlinclass TestStaticMethod {companion object {@JvmStaticfun methodWithJvmStatic() {}fun methodWithoutJvmStatic() {}}}// Java// 调用@JvmStatic修饰的方法TestStaticMethod.Companion.methodWithoutJvmStatic();// 调用未使用@JvmStatic修饰的方法TestStaticMethod.methodWithJvmStatic();
f. kotlin 的调用规范与 Java 不同, 我们可以通过@JvmName 来设计名称, 使其符合这两种语言的惯例或与各自的标准库命名保持一致。
// Utils.Kt@JvmName("isStringBlankOrEmpty")fun String?.isBlankOrEmpty(): Boolean {return this != null && this.isNotEmpty()}// Kotlin"123".isBlankOrEmpty()// JavaUtilsKt.isStringBlankOrEmpty("123");
g. 当Kotlin中field的getter/setter与方法重名时, 我们也可以使用@JvmName 来对getter/setter重新命名
// Kotlinclass Person {val height: Int = 190val name: String = "石硕"@JvmName("getNameProp")get@get:JvmName("getCountryProp")@set:JvmName("setCountryProp")val country: String = "China"fun getName() = "猜猜我是谁"}// KotlinPerson().namePerson().getName()// JavaPerson person = new Person();person.getNameProp();person.getName();
h. Java在调用Kotlin使用默认参数的方法时, 如果方法没有使用@JvmOverloads时, 则该方法只会被编译成一个拥有全部参数的方法来供Java调用.
// Kotlinfun methodWithDefault(paramsA: Int = 0, paramsB: String = "123", paramsC: Boolean = true) {}@JvmOverloadsfun methodWithDefaultAndJvmOverloads(paramsA: Int = 0, paramsB: String = "123", paramsC: Boolean = true) {}// JavamethodWithDefault(1); // 编译错误methodWithDefault(1, "456", false); // 编译成功methodWithDefaultAndJvmOverloads(1) // 编译成功
i. Kotlin中所有的异常都是非受检异常, 我们可以通过@Throws注解来通知Java调用该方法时, 需要处理的受检异常是什么.
// Kotlinfun writeToFile() {/*...*/throw IOException()}@Throws(IOException::class)fun writeToFileWithThrows() {/*...*/throw IOException()}// Javatry {writeToFile();}catch (IOException e) { // 编译错误 编译器获取不到受检异常e.printStackTrace();}try {writeToFileWithThrows();}catch (IOException e) { // 编译成功e.printStackTrace();}
j. 当Kotlin的方法中定义的参数为非空类型时, 在方法开始时会使用Intrinsics.checkParameterIsNotNull()方法, 去检查该参数是否为空, 如果为null则会抛出异常, 导致应用Crash.
因此Java在调用Kotlin中如果在Kotlin中定义的方法时, 一定要判断好是否可以传null
// Intrinsics.javapublic static void checkParameterIsNotNull(Object value, String paramName) {if (value == null) {throwParameterIsNullException(paramName);}}// Kotlinfun methodA(paramsA:Int?)fun methodB(paramsA:Int)// JavamethodA(null) // 正常运行methodB(null) // 运行时Crash
k. 当从Java中调用Kotlin中含有函数类型的方法时, 如果此函数类型的返回值是Unit, 则在Java的lambda的最后需要返回return Unit.INSTANCE;
// Kotlinfun printMethod(callback: (str: String) -> Unit) {callback("Hello World")}printMethod { println(it) } // Kotlin中不需要返回Unit.INSTANCE// JavaprintMethod(text -> {System.out.println(text);return Unit.INSTANCE; // Java中需要返回Unit.INSTANCE});
如果想避免这种这种情况只能选择不使用Kotlin的函数类型, 而使用SAM接口. 但是这样做就会使 Kotlin在调用时无法使用lambda, 只能传递使用匿名内部类
// Kotlininterface InterfaceKotlin {fun print(text: String)}fun printMethod(callback: InterfaceKotlin) {callback.print("Hello World")}// Kotlin只能使用匿名内部类调用printMethod(object : InterfaceKotlin {override fun print(text: String) {println(text)}})// Java中不需要单独返回Unit.INSTANCEprintMethod(text -> {System.out.println(text);});
官方说目前没有好的解决方案, 建议在Kotlin的方法中使用函数类型参数, 而不是选择SAM接口类型.