Kotlin语言【java和kotlin之间互相操作】

  • kotlin调用java
  • java调用kotlin
  • @JvmName
  • @JvmField
  • @JvmOverloads
  • @JvmStatic
  • @Throws
  • 函数类型



定义一个java类

public class Jhava {
	    private int hitPoints = 23423144;
	    public String utterGreeting() {
	        return "HELLO";
	    }
	    public String determinFriendshipLevel() {
	        return null;
	    }
	    public int getHitPoints() {
	        System.out.println("--------hitPoints--------");
	        return hitPoints;
	    }
	    public void setHitPoints(int hitPoints) {
	        this.hitPoints = hitPoints;
	    }
	}

kotlin调用java

//创建一个java对象
	val adversary = Jhava()
	println(adversary.utterGreeting())
	val level: String? = adversary.determinFriendshipLevel()
	//这里不确定,要使用空安全操作符
	level?.toLowerCase();
	//这里会映射回对应的java类型int
	println(adversary.hitPoints.javaClass)
	//java那边是私有的,必须要提供get方法,kotlin会调用get方法获取
	//java那边是公开的,就不需要了
	println(adversary.hitPoints)
	//这里不需要调用set方法直接赋值,条件是java那边要提供set方法
	adversary.hitPoints = 222;

java调用kotlin

比如下面的Spell的kotlin文件,当中没有定义类;

package com.yclids.android_kotlin_study.test

//在java中被当做静态变量看待
val spells = listOf("A", "B", "C", "D")

//在java中被当做静态方法看待
fun makeProclamation() = "Greeting china"

fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") {
    println("Mmm ... you hand over some delicious $leftHand and $rightHand");
}

上面的kotlin文件编译后生成的类型文件名称是SpellKt,在Java中调用如下:

//如果没有使用@file:JvmName("Spell"),就要使用SpellKt才可以【转成java带有Kt】
 SpellKt.makeProclamation();
 //java中访问kotlin中某个字段,要使用get方法,因为没有添加 @JvmField
 SpellKt.getSpells();
 //java中访问kotlin中某个方法的重载,要使用,因为没有@JvmOverloads,所以不可以重载
 SpellKt.handOverFood("left", "right");

下面就介绍@JvmName、@JvmField、@JvmOverloads等使用

@JvmName

  • 可以使用@JvmName注解指定编译类的名字
  • Kotlin顶层函数在java里都被看做静态方法看待和调用

比如:Spell.kt

//添加这个声明之后在java那边可以使用Spell了
@file:JvmName("Spell")
package com.yclids.android_kotlin_study.test

//在java中被当做静态变量看待
val spells = listOf("A", "B", "C", "D")

//在java中被当做静态方法看待
fun makeProclamation() = "Greeting china"

fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") {
    println("Mmm ... you hand over some delicious $leftHand and $rightHand");
}

在Java中可以如下使用:

public class Zion {
	    public static void main(String[] args) {
        //使用@file:JvmName("Spell")
        Spell.makeProclamation();
        Spell.getSpells();
        Spell.handOverFood("left", "right");
	    }
	}

@JvmField

  • kotlin中使用这个注解以后,字段就公开了,java可以直接访问这个字段
@JvmField
	val spells = listOf("A", "B", "C", "D")

Zion.java

public class Zion {
	    public static void main(String[] args) {
        SpellKt.makeProclamation();
        //对字段使用了@JvmField,后直接访问
        List<String> spells = SpellKt.spells;
        SpellKt.handOverFood("left", "right");
	    }
	}

@JvmOverloads

  • @JvmOverloads注解协助产生kotlin函数的重载,便于在Java中使用

kotlin中

@JvmOverloads
	fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") {
	    println("Mmm ... you hand over some delicious $leftHand and $rightHand");
	}

java中使用

SpellKt.makeProclamation();
        SpellKt.getSpells();
        //对方法使用@JvmOverloads
        SpellKt.handOverFood();
        SpellKt.handOverFood("left");
        SpellKt.handOverFood("left", "right");

@JvmStatic

  • @JvmField注解还能用来以静态方式提供伴生对象里定义的值
  • @JvmStatic注解的作用类似于@JvmField,允许你直接调用伴生对象里的函数

比如下面的kotlin中的类:

package com.yclids.android_kotlin_study.test

class Prod {
    @JvmField
    //在java中被当做普通变量看待
    val spells = listOf("A", "B", "C", "D")

    @JvmOverloads
    fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") {
        println("Mmm ... you hand over some delicious $leftHand and $rightHand");
    }

    companion object {
        @JvmField
        val MAX_SPELL_COUNT = 10
        @JvmStatic
        fun getSpellbookGreeting() = println("I am the Great Grimoire!")
    }
}

在java调用

//对字段使用了@JvmField
        List<String> spells = new Prod().spells;
        //对方法使用了@JvmOverloads
        new Prod().handOverFood();
        new Prod().handOverFood("left");
        new Prod().handOverFood("left", "right");
        //对伴生对象里的字段使用了@JvmField
        int maxSpellCount = Prod.MAX_SPELL_COUNT;
        //对伴生对象里的方法使用了@JvmStatic
        Prod.getSpellbookGreeting();

@Throws

  • 抛出一个需要检查的指定异常,java和kotlin有关异常检查的差异让@Throws注解给解决掉了
@Throws(IOException::class)
	fun acceptApology() {
	    throw IOException()
	}

在Kotlin的方法中添加上面的注解以后,就可以在Java当中捕获异常了

try {
	    //kotlin那边使用了@Throws注解,这里可以捕获异常
	    SpellBookKt.acceptApology();
	} catch (IOException e) {
	    e.printStackTrace();
	}

函数类型

  • 在java中,Kotlin函数类型使用FunctionN这样的名字的接口来表示的
  • FunctionN中的N代表值参数目。每一个FuncationN都包含一个invoke函数,专用于调用函数类型函数
    在Spell中
//定义一个函数类型
	val m: (String) -> Unit = {
	    println(it);
	}

比如上面的函数类型,在Java中就要使用Function来表示,有一个参数,那就是Function1,方法调用就用invoke

Function1<String, Unit> m = SpellBookKt.getM();
	m.invoke("两只老虎");