注册

kotlin 与java 互操作

简介


大多数情况下,你不需要关注这个问题。但是,如果你的代码中包含了部分Java代码,了解这些可能帮你解决一些棘手的问题,同时让你设计的Api更加可靠


互操作性与可空性


Java世界里所有对象都可能是null,当一个kotlin函数返回string类型值,你不能想当然地认为它的返回值就能符合kotlin关于空值的规定


kotlin


fun main() {
val my = MyClass()
val value = my.getCanNullValue()
println(value?.capitalize())
}

java


public class MyClass {
public String value;

public String getCanNullValue(){
return value;
}
}

类型映射


代码运行时,所有的映射类型都会重新映射回对应的java类型


fun main() {
val my = MyClass()
my.value = "a123"
val value = my.getCanNullValue()
println(value.javaClass)
}

结果为:class java.lang.String


属性访问


不需要调用相关setter方法,你可以使用赋值语法来设置一个java字段值了


val my = MyClass()
my.value = "a123"

@JvmName


这个注解可以改变字节码中生成的类名或方法名称,如果作用在顶级作用域(文件中),则会改变生成对应Java类的名称。如果作用在方法上,则会改变生成对应Java方法的名称。


kotlin


@file:JvmName("FooKt")
@JvmName("foo1")
fun foo() {
println("Hello, Jvm...")
}

java


// 相当于下面的Java代码
public final class FooKt {
public static final void foo1() {
String var0 = "Hello, Jvm...";
System.out.println(var0);
}
}

第一个注解@file:JvmName("FooKt")的作用是使生成的类名变为FooKt,第二个注解的作用是使生成的方法名称变为foo1


@JvmField


Kotlin编译器默认会将类中声明的成员变量编译成私有变量,Java语言要访问该变量必须通过其生成的getter方法。而使用上面的注解可以向Java暴露该变量,即使其访问变为公开(修饰符变为public)。


Kotlin


class JavaToKotlin {
@JvmField
val info = "Hello"
}

@JvmOverloads


由于Kotlin语言支持方法参数默认值,而实现类似功能Java需要使用方法重载来实现,这个注解就是为解决这个问题而生的,添加这个注解会自动生成重载方法


Kotlin


@JvmOverloads
fun prinltInfo(name: String, age: Int = 1) {
println("$name $age")
}

java


 public static void main(String[] args) {
MyKotlin.prinltInfo("arrom");
MyKotlin.prinltInfo("arrom", 20);
}

@JvmStatic


@JvmStatic注解的作用类似于@JvmField,可以直接调用伴生对象里的函数


class JavaToKotlin {
@JvmField
val info = "Hello"

companion object {
@JvmField
val max: Int = 200

@JvmStatic
fun loadConfig(): String {
return "loading config"
}
}
}

@Throws


由于Kotlin语言不支持CE(Checked Exception),所谓CE,即方法可能抛出的异常是已知的。Java语言通过throws关键字在方法上声明CE。为了兼容这种写法,Kotlin语言新增了@Throws注解,该注解的接收一个可变参数,参数类型是多个异常的KClass实例。Kotlin编译器通过读取注解参数,在生成的字节码中自动添加CE声明。


Kotlin


@Throws(IllegalArgumentException::class)
fun div(x: Int, y: Int): Float {
return x.toFloat() / y
}

Java


// 生成的代码相当于下面这段Java代码
public static final float div(int x, int y) throws IllegalArgumentException {
return (float)x / (float)y;
}

添加了@Throws(IllegalArgumentException::class)注解后,在生成的方法签名上自动添加了可能抛出的异常声明(throws IllegalArgumentException),即CE。


@Synchronized


用于产生同步方法。Kotlin语言不支持synchronized关键字,处理类似Java语言的并发问题,Kotlin语言建议使用同步方法进行处理


Kotlin


@Synchronized
fun start() {
println("Start do something...")
}

java


// 生成的代码相当于下面这段Java代码
public static final synchronized void start() {
String var0 = "Start do something...";
System.out.println(var0);
}

函数类型操作


Java中没有函数类型,所以,在Java里,kotlin函数类型使用FunctionN这样的名字的接口来表示,N代表入参的个数,一共有24个这样的接口,从Function0到Function23,每个接口都包含一个invoke函数,调用匿名函数需要调用invoke


kotlin:


val funcp:(String) -> String = {
it.capitalize()
}

java:


Function1 funcp = ArromKt.getFuncp();
funcp.invoke("arrom");

作者:Arrom
链接:https://juejin.cn/post/7039268896083279902
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册