原创

Kotlin调用Java

一、属性

Kotlin调用属性实际上就是访问getter、setter方法,Java类只要提供了getter方法,Kotlin就可以将其当成只读属性;如果Java类提供了getter、setter方法,Kotlin就可将其当成读写属性。

package test0710;

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMarried(boolean married) {
        System.out.println("调用setMarried方法,参数为" + married);
    }

    public boolean isMarried() {
        return true;
    }

    public int getAge() {
        return 100;
    }
}

package test0710

fun main(args: Array<String>) {
    val user = User()
    //操作name读写属性
    user.name = "Kotlin"
    println(user.name)
    //操作isMarried读写属性
    user.isMarried = true
    println(user.isMarried)
    //读取age只读属性
    println(user.age)
}

输出结果:

Kotlin
调用setMarried方法,参数为true
true
100

二、void和调用名为关键字的成员

Java方法返回值是void,在Kotlin中对应于Unit返回值类型。

当Java的类名、接口名、方法名等是Kotlin的关键字时,需要使用反引号对关键字进行转义。

public class InMethod {
    public void in() {
        System.out.println("in方法");
    }
}
fun main(args: Array<String>) {
    val im = InMethod()
    //调用in()方法
    im.`in`()
}

输出结果:

in方法

三、Kotlin的已映射类型

Java基本类型与Kotlin类之间的映射关系

Java基本类型 Kotlin
byte kotlin.Byte
short kotlin.Short
int kotlin.Int
long kotlin.Long
char kotlin.Char
float kotlin.Float
double kotlin.Double
boolean kotlin.Boolean

Java基本类型的包装类与Kotlin类之间的映射关系

基本类型的包装类 Kotlin类
java.lang.Byte kotlin.Byte?
java.lang.Short kotlin.Short?
java.lang.Integer kotlin.Int?
java.lang.Long kotlin.Long?
java.lang.Character kotlin.Char?
java.lang.Float kotlin.Float?
java.lang.Double kotlin.Double?
java.lang.Boolean kotlin.Boolean?

Java的常用类与Kotlin类之间的映射关系

Java的常用类 Kotlin类
java.lang.Object kotlin.Any!
java.lang.Cloneable kotlin.Cloneable
java.lang.Comparable kotlin.Comparable!
java.lang.Enum kotlin.Enum!
java.lang.Annotation kotlin.Annotation
java.lang.Deprected kotlin.Deprected!
java.lang.CharSequence kotlin.CharSequence!
java.lang.String kotlin.String!
java.lang.Number kotlin.Number!
java.lang.Throwable kotlin.Throwable!

四、Kotlin对Java泛型的转换

Kotlin不支持Java的泛型通配符语法,但提供了使用处型变来代替泛型通配符。

Java泛型和Kotlin泛型的转换关系

Java泛型 Kotlin语法
Foo<? extends Bar> Foo<out Bar!>!
Foo<? super Bar> Foo<in Bar!>!
Foo<*> Foo<out Any?>!
Foo Foo<*>

五、对Java数组的处理

Kotlin数组有一个重大的改变:Kotlin数组时不型变的。所以Array不能赋值给Array变量。Java数组是型变的,所以String[]可以直接赋值给Object[]变量。

Kotlin提供了ByteArray、ShortArray、IntArray、LongArray、CharArray、FloatArray、DoubleArray、BooleanArray数组,用于代替Java的byte[]、short[]等基本类型的数组。

Java代码如下:

public class IntArrayFun {
    public int sum(int[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }
}

kotlin代码如下:

fun main(args: Array<String>) {
    val iaf = IntArrayFun()
    //由于sum()方法需要的参数是int[]类型,因此此处需要使用IntArray对象
    val intArr = intArrayOf(2, 4, 10)
    println(iaf.sum(intArr))
}

输出结果:

16

Kotlin编译器会对数组访问进行优化,采用和Java相似的方式来访问数组元素,所以Kotlin在访问元素时没有性能损耗。

fun main(args: Array<String>) {
    val array = arrayOf(1, 2, 3, 4)
    array[2] = array[2] * 2
    for (i in array.indices) {
        array[i] += 2
    }

    for (x in array) {
        println(x)
    }
}

六、调用参数个数可变的方法

对于参数个数可变的方法,Java可以直接传入一个数组,但Kotlin不行。

Kotlin要求只能传入多个参数值,但也可通过使用*解开数组的方式来传入多个数组元素作为参数值。

下面定义一个Java方法

public class JavaVarargs {
    //定义参数个数可变的方法
    public void test(int... nums) {
        for (int i = 0; i < nums.length; i++) {
            System.out.println(nums[i]);
        }
    }
}

如果在Kotlin中有一个数组,需要使用*将数组解开成多个数组元素传入。

fun main(args: Array<String>) {
    val jv = JavaVarargs()
    jv.test(2, 4, 5)
    val intArr = intArrayOf(6, 7, 8)
    //将数组解开成多个元素
    jv.test(*intArr)
}

七、checked异常

由于Kotlin没有checked异常,对于Java中可能引发checked异常的方法、构造器,Kotlin则不会引发该异常,Kotlin既可捕获该异常,也可完全不理会该异常。

import java.io.FileInputStream

fun main(args: Array<String>) {
    //下面代码可能引发IOException(checked异常)
    //但Kotlin并不强制处理该异常
    val fis = FileInputStream("aa.txt")
    println(fis.read())
}

八、Object的处理

Java的Object对应于Kotlin中的Any。

怎样使用Object类中的方法。

1、 wait()/notify()/notifyAll()

这三个方法都是Java程序中同步监视器支持调用的方法,一般在线程通信中才会用到。

如果需要让同步监视器调用这三个方法,可以将Any转型为java.lang.Object,然后再调用这三个方法。

(foo as java.lang.Object).wait()
2、getClass(0

Object对象的getClass()方法用于获取该对象的Java类,Kotlin的对象则有两种方式来获取该对象的Java类。

    //获取foo对象的Java类
    foo::class.java
    foo.javaClass
3、clone()

要让对象重写clone()方法,需要让该类实现kotlin.Cloneable接口。


class Example:Cloneable{
    override fun clone(): Any {
        return super.clone()
    }
}
4、finalize()

Object的finalize()方法主要用于完成一些资源清理的工作,GC在回收某个对象之前,JVM会自动调用该对象的finalize()方法。

如果要重写finalize()方法,则只要在类中实现该方法即可,不需要使用override关键字。

class Foo{
    protected fun finalize(){
        //实现资源清理的逻辑
    }
}

九、访问静态成员

Kotlin没有提供static关键字,但是Kotlin提供了伴生对象来实现静态成员,因此Java类中的静态成员都可以通过伴生对象的语法来调用。

fun main(args: Array<String>) {
    //调用Runtime的静态方法
    val rt = Runtime.getRuntime()
    println(rt)
    //访问java.awt.BorderLayout的NORTH静态成员
    val str = BorderLayout.NORTH
    println(str)
}

输出结果:

java.lang.Runtime@256216b3
North

十、SAM转换

Java 8支持使用Lambda表达式来作为函数式接口的实例(这种机制被称为SAM转换),Kotlin同样支持这个功能。


import java.util.concurrent.ThreadPoolExecutor
import java.util.function.Predicate

fun main(args: Array<String>) {
    //使用Lambda表达式来创建函数式接口的对象
    val pred = Predicate<Int> { t -> t > 5 }
    val list = arrayListOf(2, 200, 101, 45, 34)
    //使用pred对List集合进行过滤
    list.removeIf(pred)
    println(list)
    //使用Lambda表达式来创建函数式接口的对象
    val rn = Runnable {
        for (i in 0..10) {
            println(i)
        }
    }
    //通过Runnable对象创建、启动线程
    Thread(rn).start()
    val executor = ThreadPoolExecutor()
    executor.execute { println("This runs in a thread pool") }
    executor.execute{ Runnable { println("This runs in a thread pool") }}
}

Java表达式只能创建函数式接口的对象,不能创建抽象类的对象,即使该抽象类只有一个抽象方法也不行;

Kotlin的Lambda表达式也只能创建函数式接口的对象,不能创建抽象类的对象。

十一、在Kotlin中使用JNI

Kotlin同样支持JNI,只不过Kotlin不使用native关键字,而是使用external关键字。

external fun foo(x : Int ) :  Double

学海无涯苦作舟

我的微信公众号.jpg

基本语法
  • 作者:HunterArley (联系作者)
  • 发表时间:2019-12-06 09:44
  • 版权声明:本网站部分内容转载于合作站点或其他站点,但都会注明作/译者和原出处。如有不妥之处,敬请指出。
  • 公众号转载:请在文末添加作者公众号二维码