一、Kotlin与Java互操作与可空性。
Kotlin与Java互操作性与可空性
Java世界里所有对象都可能是null,当一个Kotlin函数返回String类型值,你不能想当然地认为
它的返回值就能符合Kotlin关于空值的规定。
1、首先定义一个Java类
public class Jhava { public String utterGreeting() { return "hello"; } public String determineFriendshipLevel() { return null; } }
2、Kotlin代码调用Java代码
fun main() { /** * Kotlin与Java互操作性与可空性 * Java世界里所有对象都可能是null,当一个Kotlin函数返回String类型值,你不能想当然地认为 * 它的返回值就能符合Kotlin关于空值的规定。 */ val adversary = Jhava() println(adversary.utterGreeting()) /** * 返回 String! 类型的值,这里的感叹号表示返回值是String或者String? * 至于Java方法返回的是String类型值是null还是其他什么,Kotlin编译器并不知道。 * 这种模棱两可的返回值类型,我们称之为平台类型。 */ var level = adversary.determineFriendshipLevel() /** * null值问题最有可能来自互操作,所以从kotlin里调用Java代码时,一定要小心谨慎。 */ println(level?.toLowerCase()) }
输出结果如下
hello null
二、类型映射、属性访问、@JvmOverloads详解
public class Jhava { private int age = 18; public int num = 1; public String utterGreeting() { return "hello"; } public String determineFriendshipLevel() { return null; } public int getAge() { System.out.println("------getAge()-----"); return age; } public void setAge(int age) { this.age = age; } public static void main(String[] args) { /** * Kotlin顶层函数在Java里都被当作静态方法看待和调用。 */ System.out.println(Hero.makeProclamation()); Spellbook spellbook = new Spellbook(); List<String> spells = spellbook.spells; System.out.println(spells); /** * Java要支持 */ Hero.handOverFood("apple"); } }
/** * 可以使用@JvmName注解指定编译类的名字。 * 必须放在包名上面,否则报错。 */ @file:JvmName("Hero") package com.example.kotlinlearn.kotlin06 /** * @Author: ly * @Date: 2023/2/8 * @Description: */ fun main() { val adversary = Jhava() /** * 代码运行时,所有的映射类型都会重新映射成对应的Java类型 */ println(adversary.num.javaClass) /** * 属性访问 * 不需要调用相关setter方法,你可以使用赋值语法来设置一个Java字段值。 */ println(adversary.age) adversary.age = 40 println(adversary.age) handOverFood("apple") } fun makeProclamation() = "Greeting,best!" /** * @JvmOverloads 注解协助产生Kotlin函数的重载版本。设计一个可能会暴露给Java用户使用API时,记得使用 * @JvmOverloads 注解,这样,无论你是Kotlin开发者还是Java开发者,都会对这个API的可靠性感到满意。 */ @JvmOverloads fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") { println("Mmm you hand over some delicious $leftHand and $rightHand") }
输出结果如下
int ------getAge()----- 18 ------getAge()----- 40 Mmm you hand over some delicious apple and beef
三、@JvmField详解
1、使用Kotlin创建一个类
class Spellbook { /** * 在Java里,不能直接访问spells字段,所以必须调用getSpells,然而,你可以给 * Kotlin属性添加@JvmField注解,暴露它的支持字段给Java调用者,从而避免用getter方法。 */ @JvmField val spells = listOf("Magic Ms.L", "Lay on Hans") }
2、使用Java创建一个Person类
public class Person{ public static void main(String[] args) { Spellbook spellbook = new Spellbook(); List<String> spells = spellbook.spells; System.out.println(spells); } }
输出结果如下
[Magic Ms.L, Lay on Hans]
四、@JvmStatic、@Throws和函数类型操作
class Student { companion object { /** * @JvmField 注解还能用来以静态方式提供伴生对象来定义的值。 */ @JvmField val STUDENT_NAME = "Android" /** * @JvmStatic 注解的作用类似于@JvmField,允许你直接调用伴生对象里的函数。 */ @JvmStatic fun study() = "I am study Android development" } } fun main() { //Kotlin中所有的异常都是默认不捕获的,当然也可以手动添加try catch进行捕获 // Grade().doSomething() try { Grade().doSomething() } catch (e: Exception) { println("Java IOException") } println("测试") ktExceptionMethod() } /** * @Throws * 抛出一个需要检查的异常,Java和Kotlin有关异常检查的差异让@Throws注解给解决掉了, * 在编写供Java开发者调用的KotlinAPI时,要考虑使用@Throws注解,这样用户就知道怎么正确处理异常了。 */ @Throws(IOException::class) fun ktExceptionMethod() { throw IOException() } val major = { majorName: String, majorContent: String -> println("$majorName study $majorContent") }
输出结果如下
Java IOException 测试 Exception in thread "main" java.io.IOException at com.example.kotlinlearn.kotlin06.StudentKt.ktExceptionMethod(Student.kt:47) at com.example.kotlinlearn.kotlin06.StudentKt.main(Student.kt:37) at com.example.kotlinlearn.kotlin06.StudentKt.main(Student.kt)
Java类如下
public class Grade { public static void main(String[] args) { System.out.println(Student.STUDENT_NAME); System.out.println(Student.study()); try { new Grade().doSomething(); } catch (IOException e) { System.out.println("IOException"); } System.out.println("test"); try { StudentKt.ktExceptionMethod(); } catch (IOException e) { System.out.println("kotlin exception"); } /** * 函数类型和匿名函数能提供高效的语法用于组件间的交互,是Kotlin编程语言里比较新颖的特性。 * 它们简洁的语法因->操作符而实现,但Java8之前的JDK版本并不支持lambda表达式。 * 在Java里,Kotlin函数类型使用FunctionN这样的名字的接口来表示的,FunctionN中的N代表值参数目。 * 这样的Function接口有23个,从Function0到Function22,每一个FunctionN都包含一个invoke函数,专用于 * 调用函数类型函数,所以,任何时候需要调一个函数类型,都要它调用invoke()方法。 */ Function2<String, String, Unit> major = StudentKt.getMajor(); major.invoke("computer", "Knock the code"); } public void doSomething() throws IOException { throw new IOException(); } }
输出结果如下
Android I am study Android development IOException test kotlin exception computer study Knock the code