【深入kotlin】 - 与Java互操作:kotlin调用java

岳安福
2023-12-01

Kotlin 调用 Java

比如如下 Java 类:

public class Person{
	private String name;
	private boolean married;
	private int age;
	......
}

在 kotlin 中调用 Person:

fun main(args:Array<String>){
	val list = ArrayList<String>// 调用 Java 类 array list
  list.add("hello")
  list.add("world")
  
  for(item in list){ // 快速迭代
    println(item)
  }
  for(i in 0 until list.size){ // Range 
    println(list[i])
  }
  
  val person = Person()
  person.age = 20 // 调用 Person 的 set 方法
  person.isMarried = false // Boolean 属性的 set 方法稍有区别
  person.name = "zhangsan"
  
  println(person.age) // 调用 get 方法
  println(person.isMarried) // Boolean 的 get 方法
  println(person.name)
}

平台类型

在 kotlin 中为了解决 Java 中所有引用类都是可空类型的问题,将所有来自于 java 的类型称为平台类型(platform types)。对这种类型kotlin 不再执行严格的非空检查。

val list = ArrayList<String>() // ArrayList 属于“平台类型”
list.add("victor") // 如果没有此句,则 list[0] 会导致下标越界
val size= list.size
val item = list[0] // item 的类型依赖于类型推断

val str: String? = item // item 可以为空
var str1: String = item // item 是一个平台类型,在编译期 Kotlin 放弃非空检查,所以不会报错,但是运行期有可能把 null赋给 str1从而出错

数组

数组在 kotlin 中是不变,即不支持协变/逆变(out/in)。但 java 不同:

public class MyTest{
	public static void main(String[] args){
			Object[] objects = new String[2]; // 产生协变。将一个 子类 赋给了父类。
			objects[0] = 1; // 编译通过,但运行时异常。
			objects[1] = 2;
	}
}

Kotlin 中的数组更加安全,它不允许协变/逆变,你无法将一个 Array 赋给 Array(编译不通过)。数组参数也是如此。Java 中,允许将一个String[] 作为参数传给方法中的 Object[] 参数,而 kotlin 不行。除非这个方法是一个 Java 方法,这个时候可以将 Ar ray 传参给 Object[]。

在 java 中,原生类型数组,比如 int[] 可以降低装箱操作的性能开销。为了和 java 兼容,kotlin 提供了 IntArray,DoubleArray,CharArray 等原生类型数组(它们跟 Array 没有任何继承关系)来达到同样的目的。

Java 类:

public class MyArray {
	public void myArrayMethod(int[] args){ // 原生数组
		
	}
}

Kotlin 代码

fun main(args: Array<String>){
	// 调用 java 方法
  val myArray = MyArray()
  val intArray = intArrayOf(1,2,3) // 返回一个 IntArray,避免装箱拆箱操作
  val a = arrayOf(1,3,5) // Array<Int> 类型,对应 Java 的 Integer[]
  
  myArray.myArrayMethod(intArray) // 用 IntArray 对应 java 的 int[]
  array[0] = array[0]*2
}

kotlin 编译器会优化数组访问,从而降低性能开销。比如上面 array[0] = array[0]*2 这句并不会调用 get/set 方法,而是直接通过索引访问元素。

可变参数

java 中可变参数实质上就是数组,即可以通过数组方式传参,也可以通过列表方式传参。

public class MyClass {
	public void method( String... strings){}
}

在 kotlin 中调用这个方法必须要使用特殊的写法:

val myClass = MyClass()
val stringArrays = arrayOf("No 1", "over world")

myClass.method(*stringArrays)// java 的 String... 对应为 kotlin 的 String!

* 操作符叫做打散操作,将一个String数组转变成 String! 类型。

运行时异常

Java 中存在两种异常:运行时异常和非运行时异常,但在 kotlin 中,只有运行时异常。如果 java 方法抛出了一个非运行期异常,

public class MyException {
	public void method() throws IOException {
		throw new IOException("I/O 异常");
	}
}

在 kotlin 中调用该方法时,kotlin 不会强制要求你捕获这个异常:

val myException = MyException()
myException.mothod() // 编译通过

获取对象的 java 类

val clazz = MyException()::class.java // 获得实例对象对应的 java class
println(clazz) // 打印:class com.xxxx.yyy.MyException

另外一种方式:

val clazz = MyException().javaClass // 获得某实例对象对应的 java class
println(clazz) // 打印:class com.xxxx.yyy.MyException
 类似资料: