kotlin08.kotlin与java交互

1,283 阅读3分钟

kotlin调用java

可空性

java所有的对象都是可为空的,但是编译器并不知道.因此kotlin在编译期间无法进行安全检测.java返回的可空类型称为平台类型String!

//java
public class TestNull {

    public String hello(){
        return "hello";
    }

    public String helloNull(){
        return null;
    }
}


//kotlin
var j = TestNull()
j.hello().run { println(this.javaClass) }
j.helloNull()?.run { println(this.javaClass) }

如果不用安全操作符?. ,会抛出空指针异常

类型映射

在运行时,所有的kotin类型最终都会映射回java的类型.比如Int - int

属性访问

kotlin使用java的属性,不需要调用getter/setter方法.会自动映射

java调用kotlin @file:JvmName("KK")

  • 全局方法可以直接用Kotlin文件的名字+Kt来作为类名调用.实际上是因为Kotlin中的全局方法都被转化为了静态方法包含在一个以Kt结尾的类中
  • 可以通过@file:JvmName("KK")来重命名kotlin编译出来的类的名字
//TestNull.java
public class TestNull {
    public static void main(String[] args) {
        System.out.println(KotlinJavaKt.methodInKotlin());
    }
}

//kotlinJava.kt
fun methodInKotlin() = "hello I am kotlin"

//等价于
public final class KotlinJavaKt {
  
   @NotNull
   public static final String methodInKotlin() {
      return "hello I am kotlin";
   }
}

java 调用kotlin的属性 @JvmField

通过 @JvmField标记的属性,可以在java中直接访问,否则需要通过属性提供默认getter/setter方法访问.

class KotlinJava {
    @JvmField
    var kotlinProperty:String = "kotlin property"
}

public static void main(String[] args) {
   KotlinJava kj = new KotlinJava();
   System.out.println(kj.kotlinProperty);

}

java调用kotlin的方法支持重载

  • @JvmOverloads协助生成kotlin的带默认参数的方法的重载方法
  • 默认情况下,kotlin带默认构造参数的方法,是不需要传入多个参数的. 在java中调用必须传入,为了也支持默认参数,需要使用@JvmOverloads注解标记. 这个标记的作为是在编译生成的class中添加了多个重载的方法实现
fun defaultParamMethod(name:String = "jack" , age:Int = 10){
    println("$name at $age")
}

KK.defaultParamMethod("jimmy" );
//提示错误 defaultParamMethod(java.lang.String, int)' in 'KK' cannot be applied to '(java.lang.String)

//添加注解后可以正常使用
@JvmOverloads
fun defaultParamMethod(name:String = "jack" , age:Int = 10){
    println("$name at $age")
}

java 调用伴生对象方法 @JvmStatic

  • @JvmField 静态方式调用伴生对象中的属性
  • @JvmStatic 静态方式调用伴生对象中的方法
//kotlin
class KotlinJava {
    @JvmField
    var kotlinProperty:String = "kotlin property"

    companion object {
        @JvmField
        val KOTLIN_VAL = "KOTLIN_VAL"
        @JvmStatic
        fun readSomething() = print("read func in kotlin")
    }
}

//java
public static void main(String[] args) {
    System.out.println(KK.methodInKotlin());

    KotlinJava kj = new KotlinJava();
 
    
    KotlinJava.Companion.getKOTLIN_VAL();
    //没加@JvmStatic
    KotlinJava.Companion.readSomething();

    KotlinJava.readSomething();
    //加@JvmStatic
    System.out.println(KotlinJava.KOTLIN_VAL);
}

java 捕获kotlin的异常

  • 默认情况下kotlin中抛出的异常,在java中不会提示异常捕获
  • 可以通过catch(Exception) 或者添加 @Throws,让java中提示该异常
  • 如果未特殊处理,kotlin中的异常都会被转化为throwable,通过catch(XXException)无法捕获 image.png
fun exceptionTest(){
    throw IOException()
}

//java
try{
    KK.exceptionTest();
}catch (Exception e){
    System.out.println("exception found");
    e.printStackTrace();
}



@Throws(IOException::class)
fun exceptionTest(){
    throw IOException()
}

try{
    KK.exceptionTest();
}catch (IOException e){
    System.out.println("exception found");
    e.printStackTrace();
}

java调用kotlin的函数类型

  • kotlin中的函数类型和匿名函数,在java中都被转化为FunctionN来表示,N代表函数类型的参数个数.
  • FunctionN(0-22) 可以通过invoke方法触发方法调用
var anonymousMethod :(x:Int ,y:Int)->Unit = {x,y->
    println("$x - $y")
}


KK.getAnonymousMethod().invoke(10 ,20);

在android中使用kotlin

工程

新建android 工程时,语言选择kotlin,自动会添加好kotlin的依赖,主要包含

  • kotlin的构建插件 ,语言特性相关插件
buildscript {
    ext.kotlin_version = '1.6.20-RC2'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.4"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin-android' 
  • 使用库相关包括函数扩展如Strings ,Ranges,Collections等.
dependencies {
    implementation "androidx.core:core-ktx:+"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

支持viewbinding

为了简化findViewById,可以选择支持kotlin-parcelize

plugins {
    id 'com.android.application'
    id 'kotlin-parcelize'
}

import com.hch.kotlinstudy.databinding.ActivityMainBinding

class HomeActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        Log.d("KotlinStudy" , "homeactivity")

        binding.tv.text = "hch"
        binding.button.setOnClickListener{
            Toast.makeText(this , binding.tv.text , Toast.LENGTH_LONG).show()
        }
    }
}