定义在命名对象的属性或者 companion对象属性是静态的.
这些私有字段可以通过下面方式暴露给java:
@JvmField 标注;
lateinit 修饰词;
const 修饰词
属性标注 @JvmField 使得它的静态字段和本身有相同可见性.
class Key(val value: Int) {
companion object {
@JvmField
val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
}
}
// JavaKey.COMPARATOR.compare(key1,key2);// public static final field in Key class延迟初始化late-initialized属性或者 companion 对象和setter方法有相同可见性.
object Singleton {
lateinit var provider: Provider
}
// JavaSingleton.provider=newProvider();// public static non-final field in Singleton class属性带有const(in classes as well as at the top level) 被转换成静态:
// file example.kt
object Obj {
const val CONST = 1
}
class C {
companion object {
const val VERSION = 9
}
}
const val MAX = 239
In Java:
int c = Obj.CONST;
int d = ExampleKt.MAX;
int v = C.VERSION;
静态方法
Kotlin 将包级的函数解释为静态方法. Kotlin
也可以为命名对象和或者协作对象生成静态方法 ,只要加上 @JvmStatic. 如果使用这个标注,
编译器将生成类和对象自己的相同方法:
class C {
companion object {
@JvmStatic fun foo() {}
fun bar() {}
}
}
Now, foo() is static in Java,
while bar() is not:
C.foo(); // works fine
C.bar(); // error: not a static method
C.Companion.foo(); // instance method remains
C.Companion.bar(); // the only way it works
命名对象:
object Obj {
@JvmStatic fun foo() {}
fun bar() {}
}
In Java:
Obj.foo(); // works fine
Obj.bar(); // error
Obj.INSTANCE.bar(); // works, a call through the singleton instance
Obj.INSTANCE.foo(); // works too
@JvmStatic annotation can also be
applied on a property of an object or a companion object making its
getter and setter methods be static members in that object or the
class containing the companion object.
可见性
Kotlin
可见性映射到java有如下规则:
private 编译为private 成员;
private top-level 定义便以为 package-local
定义;
protected 保留 protected (注意protected可以在java相同包内访问,Kotlin
不能, 因此 ;
internal 定义变成 public 。 internal 类通过名称改写(name mangling),
使得在java中很难发生冲突,允许子类使用同名重载;
public 保留 public.
KClass
有时候你需要调用
Kotlin方法,使用 KClass参数. 没有自动从 Class 到 KClass的办法,因此不得不手动代码 Class.kotlin 扩展属性:
kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class)
Handling signature clashes with @JvmName
有时 Kotlin中函数命名, 在 JVM 需要使用另外的名字。
最可能发生在类型重名 type erasure:
fun List<String>.filterValid(): List<String>
fun List<Int>.filterValid(): List<Int>
这两函数不能被同时定义, 因为他们的 JVM
前面一样: filterValid(LLjava/util/List;. 如果想要在 Kotlin中使用, 需要其中一个
(或两个) 使用 @JvmName指定不同名字:
fun List<String>.filterValid(): List<String>
@JvmName("filterValidInt")
fun List<Int>.filterValid(): List<Int>
在Kotlin可以使用同名filterValid, 在Java
中分别使用 filterValid 和 filterValidInt.
相同的情形是,当我们需要属性和方法重名时, x 和 getX():
val x: Int
@JvmName("getX_prop")
get() = 15
fun getX() = 10
默认值重载
通常, 如果写一个 Kotlin 函数带有默认值, 在 Java
中仅仅生成一个完整的方法, 带有所有参数. 如果想要导出多个方法,
可以使用 @JvmOverloads 标注.
该标注也可用于构造器, 静态方法等等. 可用于抽象方法,
包括接口上的方法.
class Foo @JvmOverloads constructor(x: Int, y: Double = 0.0) {
@JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") {
...
}
}
// Constructors:
Foo(int x, double y)
Foo(int x)
// Methods
void f(String a, int b, String c) { }
void f(String a, int b) { }
void f(String a) { }
注意, 如果类构造参数全部带有缺省值,
即使没有 @JvmOverloads 也会生成一个无参构造器.
异常检查
Kotlin 没有异常检查. 因此, 通常,
Kotlin到Java没有异常抛出:
// example.kt
package demo
fun foo() {
throw IOException()
}
想在 Java中调用并捕获异常:
// Java
try {
demo.Example.foo();
}
catch (IOException e) { // error: foo() does not declare IOException in the throws list
// ...
}
出现 Java 编译错误,
因为 foo() 没有定义 IOException. 要解决这个问题,
使用@Throws 标注:
@Throws(IOException::class)
fun foo() {
throw IOException()
}
Null-安全
从Java调用 Kotlin 函数,
没办法阻止传入参数为 null . Kotlin 生成运行时检查所有 public 函数传递参数为非空. 这种办法使得Java代码中立刻得到NullPointerException .
Variant generics
When Kotlin classes make use
of declaration-site
variance, 在 Java 代码中有两使用选项. 看看下面的类,以及两个方法:
class Box<out T>(val value: T)
interface Base
class Derived : Base
fun boxDerived(value: Derived): Box<Derived> = Box(value)
fun unboxBase(box: Box<Base>): Base = box.value
翻译为Java代码:
Box<Derived> boxDerived(Derived value) { ... }
Base unboxBase(Box<Base> box) { ... }
问题是 Kotlin
可以调用 unboxBase(boxDerived("s")), 但Java不允许, 因为在 Java
中类 Box 决定于参数 T,
因此 Box 不是 Box.的子类。
要使得代码在java中执行,需要如下定义:
Base unboxBase(Box