### 在Java中调用Kotlin
#### 调用Kotlin中的包级函数
在Kotlin的包中直接声明的函数被称为包级函数,这些函数在编译时最终会生成一个静态的函数,在Java中调用该函数有两种形式,具体如下。
* 在编译时,包级函数会生成一个静态函数,包级函数所在的文件会生成一个名为“文件名Kt”的类,因此调用包级函数通过“文件名Kt.函数名()”的形式即可。
* 如果想要编译包级函数的类名(改成与Java类名类似),则需要在Kotlin文件中上方添加@file:JvmName("类名")注解。括号中的类名可以自己定义。
接下来我们通过一个案例来演示如何在Java中调用Kotlin中的包级函数。
1. 创建PacketFunction.kt
创建一个PackageFunction.kt文件,在该文件中创建一个包级函数add(),具体代码如【文件12-9】所示。
【文件12-9】PackageFunction.kt
```
@file:JvmName("Function")
fun add(a: Int, b: Int): Int = a + b //包级函数(顶层函数)
```
在上述代码中,第1行代码中的注解表示将该文件的类名设置为Function,同时在该文件中创建了一个包级函数add(),该函数返回两个参数的和。
>[info] **注意**
带有@file:JvmName("类名")注解的kotlin文件不能放到包目录中,否则会出现this annotation is not applicable to target 'top level function' and use site target"@file"的错误信息。
2. 创建PacketFunction.java
在PackageFunction.kt文件的同级目录中创建一个PacketFunction.java文件,在该文件中调用【文件12-9】中的包级函数add(),具体代码如【文件12-10】所示。
【文件12-10】PacketFunction.java
```
public class PacketFunction {
public static void main(String[] args) {
//PackageFunction.kt 文件未添加注解时,调用add()函数
//int result = PackageFunctionKt.add(10, 20);
//PackageFunction.kt 文件添加注解时,调用add()函数
int result = Function.add(10, 20);
System.out.println(result);
}
}
```
运行结果:
```
30
```
如果【文件12-9】中不添加@file:JvmName("Function")注解,则PacketFunction.kt文件在编译时会生成一个PackageFunctionKt类,该文件中的包级函数add()在编译时会生成一个静态函数add(),因此在Java中可以通过上述第4行代码的方式来调用add()函数。如果【文件12-9】中添加@file:JvmName("Function")注解,则需要通过上述第6行代码来调用add()函数。
>[info] **注意**
在Java中不能通过new关键字来创建Kotlin中编译后生成的PackageFunctionKt类的对象。
#### 调用Kotlin中的实例字段
在Kotlin中,调用某个类的字段时,都需要通过点的方式来调用。对于Java来说,则需要通过getXX()方法和setXX()方法来获取与设置字段的值,这是因为在Kotlin类中的字段编译时最终会生成Java代码中的getXX()方法和setXX()方法。如果想要Kotlin类中的字段编译后生成的字段不用private关键字来修饰而是通过public关键字来修饰,则需要在Kotlin类中的该字段上方添加@JvmField注解,此时在Java代码中可以通过点的方式来访问Kotlin中类的字段。接下来我们通过一个案例来演示一下在Java代码中调用Kotlin中的字段。
1. 创建Field.kt
创建一个Field.kt文件,在该文件中创建一个Person类,并在该类中创建两个字段,分别是name和age。具体代码如【文件12-11】所示。
【文件12-11】Field.kt
```
class People {
@JvmField
var name = "张三"
var age = 20
}
```
上述代码中,给name字段添加了@JvmField注解,这个注解主要可以使name字段在Java中以点的方式进行访问。
2. 创建Field.java
创建名为Field的Java文件,在该类中的main()函数中来调用【文件12-11】中的字段。具体代码如【文件12-12】所示。
【文件12-12】Field.java
```
public class Field {
public static void main(String[] args) {
People people = new People();
people.name = "李四";
people.setAge(10);
System.out.println("姓名:"+people.name);
System.out.println("年龄:"+people.getAge());
}
}
```
运行结果:
```
姓名:李四
年龄:10
```
从上述代码可以看出,第5行代码是通过person.name的形式访问Kotlin中字段的,而访问age字段时,必须要通过setAge()与getAge()的方式。
#### 调用Kotlin中的静态字段和方法
在Java中,静态方法和字段可以通过static关键字来修饰,调用时直接通过“类名.成员名”的方式进行访问。在Kotlin中没有static关键字,只能通过伴生对象的方式将字段或者方法设置为静态的。如果想要将Kotlin对象中的一些属性和方法设置为静态的,则可以将它放入伴生对象中,在Java中调用时可以通过“类型.成员”或者“类名.伴生对象.成员”的方式进行访问。接下来我们通过一个案例来演示如何在Kotlin中调用静态字段和方法,并在Java中通过一定的方式进行调用这些字段和方法。
1. 创建Static.kt
创建一个Static.kt文件,在该文件中创建一个Department类并在这个类中创建一个名为Fruit的伴生对象,在该伴生对象中创建一个静态字段name。具体代码如【文件12-13】所示。
【文件12-13】Static.kt
```
class Department {
companion object Fruit {
var name = "Apple" //静态的
@JvmStatic
fun sayHello() {
println(name)
}
}
}
```
上述代码中,在伴生对象Fruit中创建了一个静态字段name,同时也通过@JvmStatic注解创建了一个静态方法sayHello()。在Kotlin中,可以将命名对象(Object对象)或伴生对象中定义的方法通过@JvmStatic注解生成一个静态方法。
2. 创建Static.java
创建一个Static.java文件,在该文件中调用【文件12-13】中的静态字段和方法。具体代码如【文件12-14】所示。
【文件12-14】Static.java
```
public class Static {
public static void main(String[] args) {
Department.Fruit.setName("Pea"); //设置Kotlin中的静态字段
Department.Fruit.getName(); //获取Kotlin中的静态字段
Department.Fruit.sayHello(); //调用Kotlin中的静态函数
Department.sayHello(); //调用Kotlin中的静态函数
}
}
```
运行结果:
```
Pea
Pea
```
从上述代码可以看出,在Java中可以通过“类名.伴生对象名.getXX()/setXX()”的方式来访问Kotlin中的静态字段,通过“类名.伴生对象.静态方法”或“类名.静态方法”的方式来访问Kotlin中的静态方法。
#### 调用Kotlin中的集合类
Kotlin中List和MutableList是映射到Java中的List,同样Map和Set也是一样的,需要注意的是Kotlin中通过listof()方法创建的集合是不能添加和删除元素的。接下来我们通过一个案例来演示在Java中调用Kotlin中创建的一个List集合并修改集合中的元素。
1. 创建List.kt
创建一个List.kt文件,在该文件中创建一个getList()方法,该方法的返回值是一个集合,这个集合是通过listof()方法创建的。具体代码如【文件12-15】所示。
【文件12-15】List.kt
```
fun getList():List<String>{
return listOf("张三","李四","王五")
}
```
2. 创建ModifyList.java
创建一个ModifyList.java文件,在该文件中的main()方法中通过调用Kotlin中创建的getList()方法来获取List集合并修改集合中的元素。具体代码如【文件12-16】所示。
【文件12-16】ModifyList.java
```
import java.util.List;
public class ModifyList {
public static void main(String[] args) {
List<String> list = ListKt.getList();//映射到Java的List
list.set(2, "周七"); //修改集合中索引为2的元素值为周七
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
```
运行结果:
```
张三
李四
周七
```
在上述代码中,通过set()方法将list集合中的索引为2的元素修改为周七,从运行结果可以看出已经修改成功。
需要注意的是,Java中可以通过add()方法向集合中添加或修改元素,但这里不能这样写,否则在运行时会报错。
#### 显式申明Kotlin中的异常
在Kotlin中抛出一个异常,在Java中调用该异常所在的方法时,编译器不会提示有异常需要处理。如果想要在Java编译器中提示有异常,则需要在Kotlin中抛出异常的方法上方添加一个@Throws(Exception::class)注解。接下来我们通过一个案例来演示显示申明Kotlin中的异常。
1. 创建Exception.kt
创建一个Exception.kt文件,在该文件中创建一个Calculation类,在该类中定义一个divide()方法实现两个数的除法运算。具体代码如【文件12-17】0所示。
【文件12-17】Calculation.kt
```
class Calculation {
// 提示处理Kotlin 异常
@Throws(Exception::class)
fun divide(a: Int, b: Int) {
if (b == 0) {
throw Exception(" 出现了异常")
}
val result = a / b
println(result)
}
}
```
上述代码中,当divide()方法中传递的参数b为0时,程序会抛出一个异常,同时在该方法的上方添加了@Throws(Exception::class)注解,添加这个注解是为了在Java中调用这个方法时编译器会提示有异常。
2. 创建ExceptionDemo.java
创建一个Exception.java文件,在该文件中调用【文件12-17】中的divide()方法,具体代码如【文件12-18】所示。
【文件12-18】Exception.java
```
public class Exception extends Throwable {
public static void main(String[] args) {
Calculation calc = new Calculation();
try {
calc.divide(10, 0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
运行结果:
```
Exception in thread"main"java.lang.Exception:出现了异常
at com.itheima.chapter12.Calculation.divide(Exception.kt:7)
at com.itheima.chapter12.Exception.main(Exception.java:6)
```
在上述代码中,调用divide()方法时,由于编译器提示此处需要处理一个异常,因此添加了try…catch语句。如果【文件12-17】中的divide()方法上方不添加@Throws(Exception::class)注解,此时调用divide()方法,编译器不会提示这个异常,但是在程序运行时会抛出这个异常。
#### 关键字冲突的互操作
一些Kotlin关键字在Java中是最优先的标识符,例如in、Object、is等。如果在Java中使用了Kotlin中的关键字作为一个方法的名称,则可以通过反引号字符转义来调用。接下来我们通过一个案例来演示在Kotlin中如何处理关键字冲突的互操作。
1. 创建Keyword.java
创建一个Keyword.java文件,在该文件中创建一个is()方法。具体代码如【文件12-19】所示。
【文件12-19】Keyword.java
```
public class Keyword {
public boolean is(Object o) {
return true;
}
}
```
2. 创建Keyword.kt
创建一个Keyword.kt文件,在该文件中调用Java中创建的is()方法。具体代码如【文件12-20】所示。
【文件12-20】Keyword.kt
```
fun main(args: Array<String>) {
var key = Keyword()
var result = key.`is`("Hello") //通过反引号调用is()方法
println(result)
}
```
运行结果:
```
true
```
在上述代码中,由于在Kotlin中is是关键字,如果想要调用is()方法,则需要通过反引号来实现。
- 前言
- Kotlin简介
- IntelliJ IDEA技巧总结
- idea设置类注释和方法注释模板
- 像Android Studion一样创建工程
- Gradle
- Gradle入门
- Gradle进阶
- 使用Gradle创建一个Kotlin工程
- 环境搭建
- Androidstudio平台搭建
- Eclipse的Kotlin环境配置
- 使用IntelliJ IDEA
- Kotlin学习路线
- Kotlin官方中文版文档教程
- 概述
- kotlin用于服务器端开发
- kotlin用于Android开发
- kotlin用于JavaScript开发
- kotlin用于原生开发
- Kotlin 用于数据科学
- 协程
- 多平台
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 开始
- 基本语法
- 习惯用法
- 编码规范
- 基础
- 基本类型
- 包与导入
- 控制流
- 返回与跳转
- 类与对象
- 类与继承
- 属性与字段
- 接口
- 可见性修饰符
- 扩展
- 数据类
- 密封类
- 泛型
- 嵌套类
- 枚举类
- 对象
- 类型别名
- 内嵌类
- 委托
- 委托属性
- 函数与Lambda表达式
- 函数
- Lambda表达式
- 内联函数
- 集合
- 集合概述
- 构造集合
- 迭代器
- 区间与数列
- 序列
- 操作概述
- 转换
- 过滤
- 加减操作符
- 分组
- 取集合的一部分
- 取单个元素
- 排序
- 聚合操作
- 集合写操作
- List相关操作
- Set相关操作
- Map相关操作
- 多平台程序设计
- 平台相关声明
- 以Gradle创建
- 更多语言结构
- 解构声明
- 类型检测与转换
- This表达式
- 相等性
- 操作符重载
- 空安全
- 异常
- 注解
- 反射
- 作用域函数
- 类型安全的构造器
- Opt-in Requirements
- 核心库
- 标准库
- kotlin.test
- 参考
- 关键字与操作符
- 语法
- 编码风格约定
- Java互操作
- Kotlin中调用Java
- Java中调用Kotlin
- JavaScript
- 动态类型
- kotlin中调用JavaScript
- JavaScript中调用kotlin
- JavaScript模块
- JavaScript反射
- JavaScript DCE
- 原生
- 并发
- 不可变性
- kotlin库
- 平台库
- 与C语言互操作
- 与Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 调试
- FAQ
- 协程
- 协程指南
- 基础
- 取消与超时
- 组合挂起函数
- 协程上下文与调度器
- 异步流
- 通道
- 异常处理与监督
- 共享的可变状态与并发
- Select表达式(实验性)
- 工具
- 编写kotlin代码文档
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin与OSGI
- 编译器插件
- 编码规范
- 演进
- kotlin语言演进
- 不同组件的稳定性
- kotlin1.3的兼容性指南
- 常见问题
- FAQ
- 与Java比较
- 与Scala比较(官方已删除)
- Google开发者官网简介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin样品
- Kotlin零基础到进阶
- 第一阶段兴趣入门
- kotlin简介和学习方法
- 数据类型和类型系统
- 入门
- 分类
- val和var
- 二进制基础
- 基础
- 基本语法
- 包
- 示例
- 编码规范
- 代码注释
- 异常
- 根类型“Any”
- Any? 可空类型
- 可空性的实现原理
- kotlin.Unit类型
- kotlin.Nothing类型
- 基本数据类型
- 数值类型
- 布尔类型
- 字符型
- 位运算符
- 变量和常量
- 语法和运算符
- 关键字
- 硬关键字
- 软关键字
- 修饰符关键字
- 特殊标识符
- 操作符和特殊符号
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- this关键字
- super关键字
- 操作符重载
- 一元操作符
- 二元操作符
- 字符串
- 字符串介绍和属性
- 字符串常见方法操作
- 字符串模板
- 数组
- 数组介绍创建及遍历
- 数组常见方法和属性
- 数组变化以及下标越界问题
- 原生数组类型
- 区间
- 正向区间
- 逆向区间
- 步长
- 类型检测与类型转换
- is、!is、as、as-运算符
- 空安全
- 可空类型变量
- 安全调用符
- 非空断言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函数
- 函数式编程概述
- OOP和FOP
- 函数式编程基本特性
- 组合与范畴
- 在Kotlin中使用函数式编程
- 函数入门
- 函数作用域
- 函数加强
- 命名参数
- 默认参数
- 可变参数
- 表达式函数体
- 顶层、嵌套、中缀函数
- 尾递归函数优化
- 函数重载
- 控制流
- if表达式
- when表达式
- for循环
- while循环
- 循环中的 Break 与 continue
- return返回
- 标签处返回
- 集合
- list集合
- list集合介绍和操作
- list常见方法和属性
- list集合变化和下标越界
- set集合
- set集合介绍和常见操作
- set集合常见方法和属性
- set集合变换和下标越界
- map集合
- map集合介绍和常见操作
- map集合常见方法和属性
- map集合变换
- 集合的函数式API
- map函数
- filter函数
- “ all ”“ any ”“ count ”和“ find ”:对集合应用判断式
- 别样的求和方式:sumBy、sum、fold、reduce
- 根据人的性别进行分组:groupBy
- 扁平化——处理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 区间、数组、集合之间转换
- 面向对象
- 面向对象-封装
- 类的创建及属性方法访问
- 类属性和字段
- 构造器
- 嵌套类(内部类)
- 枚举类
- 枚举类遍历&枚举常量常用属性
- 数据类
- 密封类
- 印章类(密封类)
- 面向对象-继承
- 类的继承
- 面向对象-多态
- 抽象类
- 接口
- 接口和抽象类的区别
- 面向对象-深入
- 扩展
- 扩展:为别的类添加方法、属性
- Android中的扩展应用
- 优化Snackbar
- 用扩展函数封装Utils
- 解决烦人的findViewById
- 扩展不是万能的
- 调度方式对扩展函数的影响
- 被滥用的扩展函数
- 委托
- 委托类
- 委托属性
- Kotlin5大内置委托
- Kotlin-Object关键字
- 单例模式
- 匿名类对象
- 伴生对象
- 作用域函数
- let函数
- run函数
- with函数
- apply函数
- also函数
- 标准库函数
- takeIf 与 takeUnless
- 第二阶段重点深入
- Lambda编程
- Lambda成员引用高阶函数
- 高阶函数
- 内联函数
- 泛型
- 泛型的分类
- 泛型约束
- 子类和子类型
- 协变与逆变
- 泛型擦除与实化类型
- 泛型类型参数
- 泛型的背后:类型擦除
- Java为什么无法声明一个泛型数组
- 向后兼容的罪
- 类型擦除的矛盾
- 使用内联函数获取泛型
- 打破泛型不变
- 一个支持协变的List
- 一个支持逆变的Comparator
- 协变和逆变
- 第三阶段难点突破
- 注解和反射
- 声明并应用注解
- DSL
- 协程
- 协程简介
- 协程的基本操作
- 协程取消
- 管道
- 慕课霍丙乾协程笔记
- Kotlin与Java互操作
- 在Kotlin中调用Java
- 在Java中调用Kotlin
- Kotlin与Java中的操作对比
- 第四阶段专题练习
- 朱凯Kotlin知识点总结
- Kotlin 基础
- Kotlin 的变量、函数和类型
- Kotlin 里那些「不是那么写的」
- Kotlin 里那些「更方便的」
- Kotlin 进阶
- Kotlin 的泛型
- Kotlin 的高阶函数、匿名函数和 Lambda 表达式
- Kotlin协程
- 初识
- 进阶
- 深入
- Kotlin 扩展
- 会写「18.dp」只是个入门——Kotlin 的扩展函数和扩展属性(Extension Functions / Properties)
- Kotlin实战-开发Android