Android—Kotiln基础教程(九)

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

前言

在上一篇中,主要讲解了Kotlin对应的函数式编程。在这一篇中,将会讲解Kotlin与Java之间的相互调用!

话不多说,直接开始!

1、Kotlin调用Java

1.1 属性读写操作

进入TestJava

public class TestJava {
    public int getHitPoints() {
        return hitPoints;
    }

    public void setHitPoints(int hitPoints) {
        this.hitPoints = hitPoints;
    }

    private int hitPoints = 3232320;

}
复制代码

这没啥可说的,现在进入对应Kotlin文件

fun main{
	val testJava = TestJava()
    val hitPoints = testJava.hitPoints
    println(hitPoints.dec())
    println(hitPoints.javaClass.name)
}
复制代码

运行效果

3232319
int
复制代码

只要java实体类里面对应属性有get/set方法,在Kotlin这边就能直接访问以及修改对应值。

几乎没任何难度,直接看下一个!

1.2 方法访问操作

进入TestJava

public class TestJava {
    private final String TAG = this.getClass().getSimpleName();
    
    public String utterGreeting() {
        return TAG + "_utterGreeting";
    }

    public String determineFriendShipLevel() {
        return null;
    }


    public void javaException() throws IOException {
        throw new IOException("java 异常");
    }
    
    public static int getTestInt() {
        return testInt;
    }

    public static void setTestInt(int testInt) {
        TestJava.testInt = testInt;
    }

    private static int testInt;
}
复制代码

对应Kotlin

//定义私有扩展
private fun String?.default(default: String): String {
    if (this == null) {
        println("该变量为空,返回默认值")
        return default
    }
    return this
}

fun main() {
 	val testJava = TestJava()
 	println(testJava.utterGreeting())
    val level = testJava.determineFriendShipLevel()
    /*
    *  从 java 那边穿过来的值类型为String!,这表示可能返回 String 或者 String?
    *  至于从 java 方法返回是 String 还是 null 或者其他什么的,编译器并不知道,
    *  这种被称为平台类型
    *  所以在使用时,一定要小心,尽量多加空操作
    * */
    level.default("null").toUpperCase().run(::println)
    
    TestJava.setTestInt(11111) //测试java对应的静态方法是否能访问
    println(TestJava.getTestInt())
    try {
        testJava.javaException()
    }catch (a:Exception){
        println(a.message)
    }
}
复制代码

运行效果

TestJava_utterGreeting
该变量为空,返回默认值
NULL
11111
java 异常
复制代码

运行发现,Kotlin依然能够直接调用Java对应的方法、静态以及对应Java方的异常捕获!Java不需要做任何事

不过注意的是:在Java里,会有出现空的情况,所以在不确定对应Java对应的属性以及方法返回值是否为空的话,最好在Kotlin这边提前处理好,以免报错!

现在看完了Kotlin调用Java的,那看看Java调用Kotlin的?

2、Java调用Kotlin

2.1 Kotlin非伴生调用

先进入目标Kotlin类Spellbook.kt

class Spellbook {
    fun add(num1: Int, num2: Int): Int {
        return num1 + num2
    }
    var list = listOf("Magic Ms.L", "Lay on hans")
    fun acceptApology() {
        throw IOException()
    }
}
复制代码

对应java调用

public class TestJava {
    public static void main(String[] args) {
        Spellbook spellbook = new Spellbook();
        int sum = spellbook.add(12, 32);
        System.out.println("sum:" + sum);
        ArrayList<String> listStr = new ArrayList<>();
        listStr.add("hello I'm Java");
        listStr.add("hello I'm Java");
        System.out.println("list    " + spellbook.getList());
        spellbook.setList(listStr);
        System.out.println("list    " + spellbook.getList());
        spellbook.acceptApology(); //调用Kotlin那边的自定义异常
	}
}
复制代码

运行效果

sum:44
list    [Magic Ms.L, Lay on hans]
list    [hello I'm Java, hello I'm Java]
Exception in thread "main" java.io.IOException
	at Spellbook.acceptApology(Spellbook.kt:15)
	at TestJava.main(TestJava.java:51)
复制代码

狠简单,没啥可说的!直接下一个!

2.2 Kotlin伴生调用

先进入目标Kotlin类Spellbook.kt

class Spellbook {
	
    companion object {

        val spells = listOf("Magic Ms.L", "Lay on hans")

        val MAX_SPELL_COUNT = 10

        fun add(num1: Int, num2: Int): Int {
            return num1 + num2
        }
        
        fun acceptApology() {
            throw IOException()
        }

	}
}
复制代码

在之前讲解里,提到过 companion object 表示对象Spellbook 对应的伴生对象。它的意思就和Java的Static类似,表示在Kotlin里,里面的元素以及对应方法可以直接通过类名.出来。

那么看看Java是怎样调用Kotlin伴生对象里的方法与属性呢?

public class TestJava {
   public static void main(String[] args) {
        ArrayList<String> listStr = new ArrayList<>();
        listStr.add("hello Companion I'm Java");
        listStr.add("hello Companion I'm Java");

        int sum = Spellbook.Companion.add(12, 12);
        System.out.println(sum);
        System.out.println("list    " + Spellbook.Companion.getSpells());
        Spellbook.Companion.setSpells(listStr);
        System.out.println("list    " + Spellbook.Companion.getSpells());
        Spellbook.Companion.acceptApology();
   }
}
复制代码

运行效果

24
list    [Magic Ms.L, Lay on hans]
list    [hello Companion I'm Java, hello Companion I'm Java]
Exception in thread "main" java.io.IOException
	at Spellbook$Companion.acceptApology(Spellbook.kt:47)
	at TestJava.main(TestJava.java:63)
复制代码

我们看到,通过.Companion这个关键字来间歇性访问了Kotlin对应伴生对象里的属性和方法!那如果说,不想通过这个方法呢?有没有好的方法?

既然这样问了,那就肯定有的,重新改造对应Kotlin里的内容:

class Spellbook {
	
    companion object {
    
		@JvmField
        val spells = listOf("Magic Ms.L", "Lay on hans")
		
		@JvmField
        val MAX_SPELL_COUNT = 10
		
		@JvmStatic
        fun add(num1: Int, num2: Int): Int {
            return num1 + num2
        }
        
        @JvmStatic
        @Throws(IOException::class)
        fun acceptApology() {
            throw IOException()
        }

	}
}
复制代码

我们看到对应的Kotlin里面的属性以及方法都加上了对应的注解,并且acceptApology额外加了@Throws注解,这个注解表示java方调用这个方法必须要进行异常捕获,类似于在java方法后加了在这里插入add Throws

现在来看看Java使用!

public class TestJava {
   public static void main(String[] args) {
           ArrayList<String> listStr = new ArrayList<>();
        listStr.add("hello Companion I'm Java");
        listStr.add("hello Companion I'm Java");

        int sum = Spellbook.add(12, 12);
        System.out.println(sum);
        System.out.println("list    " + Spellbook.spells);
        Spellbook.spells = listStr;
        System.out.println("list    " + Spellbook.spells);
        
        try {
            Spellbook.acceptApology(); //这里不进行try catch的话就直接报错!
        } catch (IOException e) {
            e.printStackTrace();
        }
   }
}
复制代码

运行效果

24
list    [Magic Ms.L, Lay on hans]
list    [hello Companion I'm Java, hello Companion I'm Java]
复制代码

这里我们看到,之前的那个“中间商”没有了,现在java可以直接通过类名.的方式直接访问对应的方法和属性了!

那是不是就这样没了?伴生与非伴生都讲完了!Kotlin还有啥Java不能调的?或者说不能完全发挥方法特性的?

Kotlin能够给方法形参赋初始值,Java调对应的方法能赋初始值么?

来试试看:

2.3 调用形参带默认值的方法

class Spellbook {
	
    companion object {
    
	   @JvmStatic 
       fun getSpellbookGreeting(leftHand: String = "berries", rightHand: String = "beef") =
            println("Mmmm... you hand over some delicious $leftHand and $rightHand")
	}
}

fun main(){
    Spellbook.getSpellbookGreeting()
}
复制代码

先看看对应Kotlin运行效果:

Mmmm... you hand over some delicious berries and beef
复制代码

从这个运行效果上看,当Kotlin方法里对应形参带有初始值的情况下,调用对应方法,可以不用传对应参数。那用java来调调这个方法:

1.png

如图所示

在Java使用这个方法时,却没有使用到Kotlin对应特性。想要使用那个方法只能传入两个参数。

那如果说Java就是想体验对应特性呢?

也不是不可以,现在改造一下对应Kotlin代码:

class Spellbook {
	
    companion object {
    
//        /*
//        * 可以多个注解一起使用
//        * */
       @JvmStatic  //表示 该方法 在java 层 可通过 static 静态访问,也可通过实例对象访问
       @JvmOverloads //表示该方法 在java 层 已对该函数进行了重载,可不传,可传变量1或者两者都传
       fun getSpellbookGreeting(leftHand: String = "berries", rightHand: String = "beef") =
            println("Mmmm... you hand over some delicious $leftHand and $rightHand")
	}
}

fun main(){
    Spellbook.getSpellbookGreeting()
}
复制代码

在这额外加了新的注解:@JvmOverloads,现在回到Java试试看哇:

2.png

如图所示

到Java这边也体验到了Kotlin对应的特性。是不是很简单哇。

结束语

好了,本篇到这里就结束了!同时Kotlin对应的基础教程到这也结束了!相信看到这里的小伙伴,已经具备了Java转Kotlin的基础能力!读者也可尝试将Java项目逐步转移至Kotlin!反正它俩能够相互调用!

从下一篇开始,将会开启Kotlin进阶教程——协成!编译器也将从Idea转向我们熟悉的AS!

猜你喜欢

转载自juejin.im/post/7031092740869390366