Kotlin 之旅8 Kotlin与Java共存
###基本互操作
####属性的读写
#####Kotlin能够自动识别Java的Getter与Setter,因此Kotlin中可以使用.的方式去使用Java类的属性:
//Java中的类
public class JavaBean {private int i;public int getI() {return i;}public void setI(int i) {this.i = i;}
}//Kotlin中可以直接通过.操作符去访问Java的属性
val bean = JavaBean()
bean.i = 10
println(bean.i)
复制代码
#####Java操作Kotlin的属性
//Kotlin中的Bean,注意属性为var的时候,在Java中才会有set方法生成
data class KotlinBean(var i: Int)//在Java中可以访问Kotlin的Bean,通过getter/setter
KotlinBean bean = new KotlinBean(0);
bean.setI(10);
System.out.println(bean.getI());
复制代码
####空类型
Kotlin在编译的时候,会对值进行空检查,但是在Java里面没有。所以在Kotlin操作Java代码的时候就会遇到平台类型的问题,这时候开发者需要自己确保非空。
当然可以通过下面两种注解来解决这个问题:
@Nullable -- 相当于Kotlin中的可空类型?
@notnull -- 相当于Kotlin中的一般非空类型
复制代码
####函数的调用
Kotlin中的包级函数,Kotlin在编译的时候会为这些包级函数生成一个类。在Java中就是相当于静态方法的调用。
扩展方法:带Receiver的静态方法
运算符重载:带Receiver的对应名称的静态方法
复制代码
####常见注解
@JvmField 将属性编译成Java变量
@JvmStatic 将对象的方法编译成Java静态方法
@JvmOverloads 默认参数生成重载方法
@JvmName 指定Kotlin文件编译后的类名,默认是文件名+Kt
复制代码
####NoArg与Allopen
生成无参数构造支持Jpa注解,如@EntityAllopen去掉final支持Spring注解,例如@Component
支持自定义注解类型,例如@PoKo
复制代码
####泛型
通配符Kotlin的*对应Java的?因为Kotlin中?的用处多协变与逆变out、in与Java不一样:ArrayList<out String>
没有Raw类型Java中的List相当于Kotlin中的List<*>
复制代码
###SAM转换
SAM转换就是,当Kotlin使用Java接口的时候,当接口里面只有一个方法,那么就可以用Lambda表达式代替。
例如,我们有下面的Java代码:
public class SamJava {private List<Runnable> mRunnables = new ArrayList<>();public void addTask(Runnable runnable) {mRunnables.add(runnable);System.out.println("add:" + runnable);System.out.println(mRunnables.size());}public void removeTask(Runnable runnable) {mRunnables.remove(runnable);System.out.println("remove" + runnable);System.out.println(mRunnables.size());}}
复制代码
那么在Kotlin中可以有两种方式调用,其中,第二种方式就是SAM转换:
fun main(args: Array<String>) {val sam = SamJava()sam.addTask(object : Runnable {override fun run() {println("run1")}})//sam转换sam.addTask { println("run2") }
}
复制代码
####SAM转换的注意事项
SAM转换的原理:通过分析Kotlin的字节码的时候发现,编译器编译成字节码的时候,会将Lambda转换为对应的接口对象。
因此在使用SAM转换的时候就需要注意了,SAM转换实际上是会创建不同的接口对象,对象会存在多个,如下面的代码,Task不能够正确移除:
fun main(args: Array<String>) {val sam = SamJava()val lambda = {println("run")}sam.addTask(lambda)sam.addTask(lambda)sam.removeTask(lambda)sam.removeTask(lambda)
}
复制代码
打印的结果是:
add:com.nan.sam.SamKotlinKt$sam$Runnable$13141d62@2f0e140b
1
add:com.nan.sam.SamKotlinKt$sam$Runnable$13141d62@7440e464
2
removecom.nan.sam.SamKotlinKt$sam$Runnable$13141d62@49476842
2
removecom.nan.sam.SamKotlinKt$sam$Runnable$13141d62@78308db1
2
复制代码
可以发现,在每次进行SAM转换的时候,都创建了不同的Runnable对象,因此remove不成功。
####拓展
SAM转换是对Java代码的转换,但是在中使用接口的时候,就必须要使用传统的方式了:
fun main(args: Array<String>) {val samKtlin = SamKotlin()samKtlin.addTask(object : Runnable {override fun run() {}})
}class SamKotlin {private val mRunnables = ArrayList<Runnable>()fun addTask(runnable: Runnable) {mRunnables.add(runnable)println("add:" + runnable)println(mRunnables.size)}fun removeTask(runnable: Runnable) {mRunnables.remove(runnable)println("remove" + runnable)println(mRunnables.size)}}
复制代码
但是可以通过类型别名的方式来实现类似SAM转换的功能:
//定义类型别名
typealias Runnable = () -> Unitfun main(args: Array<String>) {val samKtlin = SamKotlin()samKtlin.addTask {println("run")}
}
复制代码
但是这样做的话,在Java中使用由会比较麻烦:
SamKotlin samKotlin = new SamKotlin();
samKotlin.addTask(new Function0<Unit>() {@Overridepublic Unit invoke() {return null;}
});
复制代码
###正则表达式
Java中使用正则表达式
String source = "Hello, This my phone number: 010-12345678. ";
String pattern = ".*(\\d{3}-\\d{8}).*";
Matcher matcher = Pattern.compile(pattern).matcher(source);while(matcher.find()){System.out.println(matcher.group());System.out.println(matcher.group(1));
}
复制代码
Kotlin中使用正则表达式:
val source = "Hello, This my phone number: 010-12345678. "
val pattern = """.*(\d{3}-\d{8}).*"""
val matcher = Pattern.compile(pattern).matcher(source)while (matcher.find()) {println(matcher.group())println(matcher.group(1))
}
复制代码
需要注意的是,Kotlin中有raw String,用三引号括起来。
也可以使用Kotlin提供的Regex类,写出更有Kotlin风格的代码:
val source = "Hello, This my phone number: 010-12345678. "
val pattern = """.*(\d{3}-\d{8}).*"""Regex(pattern).findAll(source).toList().flatMap(MatchResult::groupValues).forEach(::println)
复制代码
###集合框架
以List为例子,Kotlin中可以使用Java的集合框架:
val list = ArrayList<String>()//注意不同导包
list.add("haha")
list.removeAt(0)
复制代码
######Tips:Kotlin中对List进行了优化,比如添加了removeAt,实质上是映射了remove方法。
通过点击源码可以发现,ArrayList实际上是使用了Java的ArrayList:
@SinceKotlin("1.1") public typealias ArrayList<E> = java.util.ArrayList<E>
复制代码
Kotlin中可以通过xxxOf方法去创建集合,返回的是Kotlin内部定义的接口,是不可变的集合,并没有提供add等方法:
val list = listOf("1", "2", "3")
val map = mapOf("1" to "1","2" to "2","3" to "3")
复制代码
但是Java中访问这些集合的时候是当做普通的集合来使用的,因此操作的时候就会抛异常:
//Kotlin代码
object Test {val list = ArrayList<String>()
}//Java代码
List<String> list = Test.INSTANCE.getList();
list.add("1");
复制代码
程序运行不了,控制台输出:
Exception in thread "main" java.lang.UnsupportedOperationException: Operation is not supported for read-only collectionat kotlin.collections.EmptyList.add(Collections.kt)at com.nan.sam.SamJava.main(SamJava.java:24)
复制代码
###IO操作
以文件的读取为例子,先看看Java版本的:
BufferedReader bufferedReader = null;
try {bufferedReader = new BufferedReader(new FileReader((new File("build.gradle"))));String line;while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}
} catch (Exception e) {e.printStackTrace();
} finally {try {if (bufferedReader!=null) {bufferedReader.close();}} catch (Exception e) {e.printStackTrace();}
}
复制代码
然后是Kotlin版本:
val bufferedReader = BufferedReader(FileReader(File("build.gradle")))
var line: Stringwhile (true) {line = bufferedReader.readLine() ?: breakprintln(line)
}bufferedReader.close()
复制代码
比较突出的不同点是,Kotlin中不能像Java一样“line = bufferedReader.readLine()”,line不会作为返回值。因此只能用传统的写法。
另外也可以通过use关键字进行简化:
val bufferedReader = BufferedReader(FileReader(File("build.gradle"))).use {var line: Stringwhile (true) {line = it.readLine() ?: breakprintln(line)}
}
复制代码
其中use是Closeable的一个扩展方法:
@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {var closed = falsetry {return block(this)} catch (e: Exception) {closed = truetry {this?.close()} catch (closeException: Exception) {}throw e} finally {if (!closed) {this?.close()}}
}
复制代码
最后,在读取这种小文件的时候,可以直接使用File的扩展方法:
File("build.gradle").readLines().forEach(::println)
复制代码
readLines的定义如下:
public fun File.readLines(charset: Charset = Charsets.UTF_8): List<String> {val result = ArrayList<String>()forEachLine(charset) { result.add(it); }return result
}public fun File.forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit): Unit {// Note: close is called at forEachLineBufferedReader(InputStreamReader(FileInputStream(this), charset)).forEachLine(action)
}
复制代码
###装箱与拆箱
Java中有装箱与拆箱之分,例如int与Integer,但是Kotlin中统一用Int代替,一切的转换由编译器完成。
但是偶尔会遇到Java代码翻译成Kotlin代码的时候有歧义的情况,解决办法就是用Java代码去实现这个功能,而在Kotlin中使用。关于这类问题实际中遇到比较少,因此不仔细说明。
如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:
我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)。
Kotlin 之旅8 Kotlin与Java共存相关推荐
- kotlin 调用java_从Kotlin调用Java代码
Kotlin代码与Java代码完全兼容. Java代码在Kotlin代码中轻松调用,Kotlin代码也可以通过Java代码的正常方式调用. 从Kotlin调用Java代码 从Kotlin文件调用Jav ...
- Kotlin传递可变长参数给Java可变参数方法
定义Java可变参数方法 package com.tcl.john.studymvvm.utils;/*** 调用Java方法的工具类* Created by ZhangJun on 2017/10/ ...
- 学习Kotlin(一)为什么使用Kotlin
推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...
- 手把手教你学Kotlin (1): JetBrains的Kotlin Educational Tool下载、安装和 Kotlin Koans的安装和使用
文章目录 前言 1.Kotlin Educational Tool下载.安装 2.Kotlin Koans的安装和使用 前言 此教程面向没有Kotlin基础的程序员或者学生 1.Kotlin Educ ...
- 【Android NDK 开发】Kotlin 语言中使用 NDK ( 创建支持 Kotlin 的 NDK 项目 | Kotlin 语言中使用 NDK 要点 | 代码示例 )
文章目录 一.创建支持 Kotlin 的 NDK 项目 二.Kotlin 语言中使用 NDK 要点 1.加载动态库 2.声明 ndk 方法 3.Project 下的 build.gradle 配置 4 ...
- 第3章 Kotlin语言基础 《Kotlin 极简教程》
2019独角兽企业重金招聘Python工程师标准>>> 第3章 Kotlin语言基础 掌握基础,持续练习 学习任何东西,都是一个由表及里的过程.学习一门编程语言也一样.对于一门编程语 ...
- Kotlin入门(1)搭建Kotlin开发环境
Kotlin做为一门编程语言,已经出现好几年了,但此前在国内并不闻名.自从5月份谷歌宣布它成为Android的官方开发语言之后,Kotlin猛然窜红了,虽说短期内Kotlin无法取代Java,但对于一 ...
- kotlin 扩展函数_在 Kotlin 中“实现”trait/类型类
本文原发于我的个人博客:https://hltj.me/kotlin/2020/01/11/kotlin-trait-typeclass.html.本副本只用于知乎,禁止第三方转载. trait 与类 ...
- kotlin null_Kotlin Null安全– Kotlin可空
kotlin null In this tutorial, we'll look into Kotlin Null Safety. NullPointerException is one of the ...
最新文章
- 百度编辑器(ueditor)上传图片
- 转载 React.createClass 对决 extends React.Component
- Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
- EBPY0106是什么意思
- linux下修改rm命令防止误删除
- 关于select中fd_set变量的一些通俗宏解释
- 【环境搭建001】ubuntu 和 win7 在vm 下的文件夹共享实践
- Octopress使用中经验总结
- wdcp v2.5.15 php版本,linux服务器/虚拟主机管理系统wdcp v2.5.6版本发布
- 用UltraISO制作CentOS的DVD光盘启动盘 安装系统
- vs2008 web创作组件安装失败
- CSS的border属性绘制简单三角形、边框三角形
- 如何成为靠谱的DotNet/C#程序员 (sunxiunan)(zz)
- aruba无线ap认证服务器,Aruba无线AP及AC配置.doc
- matlab angle函数
- SEOer未来发展的两个方向
- 为什么近视人群需要戴变色镜片?
- transform video to frames/提取视频中的每一帧
- 主谓宾定状补口诀及练习题
- 精品站长网交易系统源码/虚拟交易网站程序源码+全套打包2G