Kotlin与Java互操作要注意的问题

2023-11-20

个人使用Kotlin开发也有一年了,一直想总结一下Kotlin和Java互相操作要注意的问题,偶然看到一篇总结不错的文章就直接搬运过来了。

前言

目前kotlin是谷歌首推的开发Android的语言,但由于历史原因,我们绝大部分项目依旧还是以Java为主的,也就是说存在Java和Kotlin两种语言同时开发的情况。

有人会说把老项目全部翻译成Kotlin,的确可以怎么做,但是成本还是挺大的。我们只能一点一点慢慢的向kotlin语言迁移。

那么在迁移的过程中就避免不了Java和Kotlin相互调用的情况。即Kotlin调用Java或者Java调用Kotlin。下面我们就来具体看下两者之间相互操作的一些解决方案。

kotlin调用java

可空性(Nullability)

Java默认有数值可空性而kotlin没有,所以在调用Java的方法的时候不知道会不会收到空值。
所以我们在Kotlin中调用Java的时候需要添加 ?或者 !来告诉Kotlin有可能出现空值。

比如这里有一个Java方法,接受一组字符串后返回一组做字符串:

public Set<String> toSet(Collection<String> elements){
    //TODO
}

那么Kotlin在调用的时候是不能确定输入和输出是否可为空的。就需要使用?或者 !来​辅助判断。​

为了方便Kotlin调用,我们通常使用 @NotNull 注解来标识Java代码的非原始参数、字段、返回值。

@NotNull
Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements){
    //TODO
}

这个Kotlin在调用的时候就明确知道不能为空,这里我们使用的是jetBrain的 @NotNull注解,当然还有其他选择,如下图:

这里还是推荐使用JetBrain或者Android的注解。

前缀属性:(getter、setter)

如果是使用Java bean,那么我们在Kotlin中调用就没有什么问题。

如果你的空参数方法是以get开头的,那么Kotlin就知道这是getter,就可以通过属性名来访问它。
相同的如果是由set开头的单一参数方法,那么Kotlin就知道这是setter,就通过属性名直接赋值。
当然is的工作原理也是和它们类似的。

我们定义一个Java bean:

class User {
    
    private String name;
    private int age;

    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;
    }
}

Kotlin中访问

val user = User()
user.name = "四爷" //赋值
val age = user.age //获取age字段值

关键字(keywords)

kotlin中有很多系统定义的关键字如 fun is in objects、typeof、val、var、when、typealias等。

这些关键字在java是可以被使用的,但是在kotlin却是不行的。

函数或者参数使用了这些关键字,那么kotlin在调用的时候会出现一些问题,比如Java中定义了一个方法名叫 is 的方法。那么在Kotlin中直接调用就会报错。

那么最简单的方法就是重命名Java方法,但如果调用的是三方库的方法,就很难去重命名了。
所以我们另一种解决方式是在Kotlin调用java方法的时候加上 `` 反引号来使用。

 Utils.`is`()

但是我们如果能重命名还是重命名,以防止代码出现太多的符号。

避免在任何扩展方法和扩展属性上使用Any

运算符重载(operator Overloading)

在Java不存在运算符重载,而kotlin有。比如:

a+b => a.plus(b)

在kotlin中将运算符 + 翻译为了方法 plus。

如果在Java中使用了同样的方法名称,比如 加(plus)、 减(minus)或者其他运算符名称,那么请务必确保他们与运算符兼容,避免意外调用他们。

Java调用Kotlin

JvmName & JvmMultifileClass

当我们在迁移的时候会将Java的工具类翻译为Kotlin拓展函数或者顶层函数。但是这样处理之后,在Java文件中是无法直接调用的,此时我们需要加注解 @file:JvmName(“文件名称”):

Ext.kt文件

@file:JvmName("ExtUtils")
package com.demo.javaAndKotlin

fun a(): String {
    ...
}

fun b(): String {
    ...
}

这里我们将名称命名为ExtUtils。此外,我们可能还有其他的顶层函数或者扩展函数。按照上面这种方式我们也可以指定一个其他的名称,但是如果我们也想使用ExtUtils这个名称的时候会报错:

Duplicate JVM class name 

此时我们需要在不同的文件中加入新的注解 @file:JvmMultifileClass 。意思是将所有的文件合并到一个新的名称为ExtUtils文件中。

ExtOther.kt文件

@file:JvmMultifileClass
@file:JvmName("ExtUtils")
package com.demo.javaAndKotlin

fun c(str: Any): String {
   ...
}

我们在Ext.kt文件中也加入@file:JvmMultifileClass注解,我们就可以在Java文件中直接使用ExtUtils来调用 a(),b(),c()方法了。

JvmField

在 kotlin中我们使用的数据类即 data class 是不需要指定getter和setter的,可以直接通过字段名来访问它们。但是如果是在Java文件中调用data class依旧是需要使用getter和setter方法进行调用的。这里我们是可以修改他们的,那就是使用 @JvmField 注解,通过注解,可以直接将字段暴露出去进行访问。​

data class Person(

    @JvmField var name: String,
    @JvmField var age: Int
)

//java中调用
Person person = new Person("",1);
person.name = "";
person.age = 10;

但是也有例外就是lateinit修饰的字段会自动暴露,无需指定@JvmField注解。还有const修饰的字段也是一样会自动暴露。

另外,如果我们想在Java中调用setName的时候修改这个属性名称不叫setName,这里我们需要使用@set:JvmName 注解。同理修改getName使用@get:JvmName 。需要注意的是,指定了@set:JvmName或者@get:JvmName注解后不需要在指定@JvmField了。

data class Person(

    @set:JvmName("changeName")
    var name: String,
    @JvmField var age: Int,
    @get:JvmName("likesPink")
    var likesPink: Boolean
){
    lateinit var address:String
}

JvmStatic

当我们将Java文件的静态方法迁移到Kotlin中时,我们会将其放在 companion object中,但是这样处理之后在Java文件中无法直接调用,得通过companion对象实例方法来调用。

class MyService {
    internal fun doWork() {
        ...
    }

    companion object {
        fun schedule(context: Context) {
            ...
        }
    }
}

//在Java中调用
MyService.Companion.schedule(this);

幸运的是Kotlin提供了 @JvmStatic 注解。他会让Kotlin在编译器完成类封装后生成一个静态方法。

class MyService {
    internal fun doWork() {
        ...
    }

    companion object {
        @JvmStatic
        fun schedule(context: Context) {
            ...
        }
    }
}

//在Java中调用
MyService.schedule(this);

JvmOverloads

在Kotlin中我们可以给函数的参数设置默认值,即默认参数。但是这个功能在Java中是没有的。如果不做任何处理,那么在Java中调用函数的时候,就必须每个参数都要传入。那么我们设置的默认参数就没有任何意义了。

所以,Kotlin给我们提供了 @JvmOverloads注解,使用这个注解后,会让Kotlin编译器按照从左向右的顺序依次为每一个可选参数生成重载。

@JvmOverloads
fun Bitmap.resize(width: Int, height: Int = 200) {

}

//java调用
ExtUtils.resize(bitmap,100);

这里我们在Kotlin中很容易就理解了Bitmap.resize方法的含义,但是ExtUtils.resize这样调用的时候,方法名不够明确。所以我们可以使用@JvmName注解来指定名称。

@JvmName("resizeBitmap")
@JvmOverloads
fun Bitmap.resize(width: Int, height: Int = 200) {

}
//java调用
ExtUtils.resizeBitmap(bitmap,100);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin与Java互操作要注意的问题 的相关文章

随机推荐

  • logback-spring.xml中三种相对路径生成的日志文件的位置

    logback spring xml中关于路径配置的三种写法 写法1
  • 大屏图表,ECharts 从“熟练”到入门

    阅读本文 你将 了解 配置驱动 的思想 理解 Echarts 基本概念 了解 graphic 和 动画基本玩法 了解 Echarts 基底组件的封装的思路 一 不是标题党 Echarts 简历上人均 熟练 公司最近在招外包 而因为目前大屏的
  • java自动识别文件编码格式UTF-8,UTF-8无BOM,GBK

    背景 在解读properties配置文件时windows操作系统编辑过的内容上传后总是无法通过键获取文件中内容 讲过分析是文件的编码格式为UTF 8带BOM的 因此通过该程序获取文件编码格式 import java io BufferedI
  • ES6阮一峰入门教程

    地址为 https es6 ruanyifeng com
  • visual studio 一直显示正在准备解决方案

    首先重启电脑 无法解决的情况下执行以下步骤 Kill Visual Studio Open Visual Studio without loading a solution Disable AnkhSvn as Source Control
  • vue动态绑定video视频src问题解决

    做个项目 视频部分需要先后台上传 然后前端页面显示 然后就遇到了视频动态获取地址的问题 一开始想着很简单 使用v model双向绑定就行了 结果试了下并不行 后面开始度娘 尝试过很多人说的 refs解决 结果并不行 虽然浏览器中看地址确实绑
  • 设计模式(2)

    2 2 结构型模式 结构型模式一共有七种 其中 适配器模式和装饰模式统称为包装模式 装饰模式和代理模式的类图基本相同 但目的不同 这些有相似目的或者有相似结构的模式需要对其概念辨析清楚 才能较好地掌握 下面将对结构型模式分别进行介绍 2 2
  • C++启蒙笔记(八)---类继承、动态内存分配

    目录 一 基本概念 1 1派生类 1 2 继承关系 二 常规写法 2 1 头文件 2 2 类实现 2 3 主程序 2 4 编译及显示 三 多态公有继承 3 1 虚方法 3 2 抽象基类 3 3 多重继承MI 四 动态内存分配 4 1 头文件
  • PyTorch实现Logistic Regression

    1 PyTorch基础实现Logistic regression import torch from torch autograd import Variable torch manual seed 2 x data Variable to
  • Python in Visual Studio Code 2023年9月更新

    作者 Courtney Webster Program Manager Python Extension in Visual Studio Code 排版 Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Py
  • 黑白图片上色算法

    效果图 Marked B W image Result Marked B W image Result Marked B W image Result Marked B W i
  • win10 系统锁屏壁纸的目录

    路径 C Users 你自己的用户名 AppData Local Packages Microsoft Windows ContentDeliveryManager cw5n1h2txyewy LocalState Assets 查看 需要
  • 使用php简单网页抓取和内容分析,PHP抓取及分析网页的方法详解

    本文实例讲述了PHP抓取及分析网页的方法 分享给大家供大家参考 具体如下 抓取和分析一个文件是非常简单的事 这个教程将通过一个例子带领你一步一步地去实现它 让我们开始吧 首先 我首必须决定我们将抓取的URL地址 可以通过在脚本中设定或通过
  • python 去除所有的中文 英文标点符号

    去除英文标点符号 python的string模块下的 punctuation 包含所有的英文标点符号 所以用replace 一下就可以去除 代码示例 import string stri today is friday so happy p
  • MacOS中清除原有ssh公钥方法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 用ssh的跳转登录服务器后 ssh会把你每个你访问过计算机的公钥 public key 都记录在 ssh known hosts 当下次访问相同计算机时 SSH会核对公钥
  • smbms 获取角色操作,角色管理实现

    为了我们职责统一 可以把角色的操作单独放在一个包中 和pojo中的对应 RoleDao 接口 package com Li dao role import com Li pojo Role import java sql Connectio
  • 数据结构--树存储结构 & 深度优先遍历 & 广度优先遍历 通俗易懂

    树的概念 首先 树是一种常用的非线性数据结构 是以边 Edge 相连的节点 Node 的集合 每个节点存储对应的值 当存在子节点时与之相连 根节点 是树的首个节点 边 所有节点都由边相连 用于标识节点间的关系 叶子结点 树的末端节点 它们没
  • 10讲学会C语言之第五讲:函数

    文章目录 前言 一 计算圆柱体积 二 数字金字塔 三 结构化程序设计 四 复数运算 五 作业 前言 大家好 我是卷卷 本节课是第五讲 函数 本节课主要有这五个部分 计算圆柱体积 数字金字塔 结构化程序设计 复数运算 作业 文末附课程资源和讨
  • ajax.beginform json,javascript - How to use Ajax.BeginForm MVC helper with JSON result? - Stack Over...

    I m trying to use the ASP NET MVC Ajax BeginForm helper but don t want to use the existing content insertion options whe
  • Kotlin与Java互操作要注意的问题

    个人使用Kotlin开发也有一年了 一直想总结一下Kotlin和Java互相操作要注意的问题 偶然看到一篇总结不错的文章就直接搬运过来了 前言 目前kotlin是谷歌首推的开发Android的语言 但由于历史原因 我们绝大部分项目依旧还是以