将 kotlin 编译成 java
先来个题外话,我们如何看 kotlin 对应的 java 代码,kotlin 最终还是要编译成 java class 在 JVM 上运行的,有时我们的确是想看看用 kotlin 写完的代码编译完了是什么样子,这样有助于我们理解 kotlin 语法
其实很简单,AS tools 工具里面有提供
-
tools -> Show kotlin Bytecode
-
点击 Decompile
ok ,这样就行了
kotlin 实现静态的方式
在 kotin 语言中其实没有 java static 的这个概念,基本都是用一个静态对象来模拟 class 的静态属性和方法,目前有4种实现方式:
- companion object - 伴随对象,声明单例的方式
- @JvmField + @JvmStatic 注解 - 使用注解标签声明 static 的部分
- object 单例 - 静态单例其实和 companion object 类似
- const - 包内唯一性,脱离类的束缚,kotlin 的特性,在 java 中会编译生成一个 kotlin.kt 的文件专门对齐提供支持
companion object
companion object 伴随对象这是我们在 kotlin 中最常用的方式了吧,在 companion object 里面我们即可以声明属性,也可以声明方法,kotlin 中的调用方式感觉和 java 的 static 一样,举个例子看下面:
class BookKotlin {
var name: String = "AA"
fun speak() {}
companion object instance {
var nameStatic: String = "BB"
fun speakStatic() {}
}
}
kotlin 中使用如下:
看上面图,我们在 kotlin 中使用时感觉的确是和 java 中的 static 一样,静态参数方法和成员参数方法能有效区别开来,下面我们来看看 java 中使用
java 中使用如下:
kotlin 的使用 ok ,但是一到 java 上就全变了,为啥,因为 kotlin 最终也是会编译成 java 文件去 JVM 运行的,kotlin 并没有提供自己特有的 VM ,所以kotlin 代码还是要转换成 java 代码的,要不 kotlin 怎么宣传 kotlin 和 java 可以实现无缝调用
kotlin 中所有的成员变量,不管是不是 static 的都有 get/set 方法,另外 kotlin 并没有把我们声明的静态参数和方法声明成 static 的,而是通过 instance 这个静态对象中转使用的,这就让我们迷惑了,kotlin 变成成 java 之后到底上啥样的,会不会和我们的初衷不同,影响我们使用
instance 这个静态对象的名字是采用 companion object 后面跟的名字,可以不写,不写的话默认就是 INSTANCE(版本不同会有变化)
下面我们把 kotlin 转换成 java 代码来一探究竟
把 kotlin 代码转成 java:
public final class BookKotlin {
private static String nameStatic = "BB";
public static final BookKotlin.instance instance = new BookKotlin.instance((DefaultConstructorMarker)null);
private String name = "AA";
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "");
this.name = var1;
}
public final void speak() {
}
public static final class instance {
@NotNull
public final String getNameStatic() {
return BookKotlin.nameStatic;
}
public final void setNameStatic(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "");
BookKotlin.nameStatic = var1;
}
public final void speakStatic() {
}
private instance() {
}
// $FF: synthetic method
public instance(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
看到 java 代码后,大家都彻底清楚了吧, companion object 伴随对象真不是白叫的,真的是个对象,在 class 内部添加一个 static final class 的静态内部类实现对象来模拟 static 特性
@JvmField + @JvmStatic 注解
上面我们见识了 companion object 伴随对象,那么 kotlin 是不是真的无法实现 static 了,也不是,kotlin 还是提供了相关办法,这就是 @JvmField + @JvmStatic 注解,其意思是声明成员和方法使用 JVM 提供的特性
- @JvmField - 修饰静态变量
- @JvmStatic - 修饰静态方法
- @JvmField 和 @JvmStatic 只能写在 object 修饰的类或者 companion object 里,写法虽然有些别扭,但是效果是真的是按 static 来实现的
我们把上面的代码修改下:
class BookKotlin {
companion object {
@JvmField
var nameStatic: String = "BB"
@JvmStatic
fun speakStatic() {
}
}
var name: String = "AA"
fun speak() {}
}
kotlin 中使用如下:
java 中使用如下:
把 kotlin 代码转成 java:
public final class BookKotlin {
@JvmField
public static String nameStatic = "BB";
@JvmStatic
public static final void speakStatic() {
Companion.speakStatic();
}
public static final BookKotlin.Companion Companion = new BookKotlin.Companion((DefaultConstructorMarker)null);
private String name = "AA";
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "");
this.name = var1;
}
public final void speak() {
}
public static final class Companion {
@JvmStatic
public final void speakStatic() {
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
object 单例
kotlin 自身提供了一种单例实现方式:object ,直接用来修饰 class ,用 object 修饰的类不能 new 对象,只能使用 object 提供的单例
object BookKotlin {
var name: String = "AA"
fun speak() {}
}
kotlin 中使用如下:
java 中使用如下:
把 kotlin 代码转成 java:
public final class BookKotlin {
private static String name;
public static final BookKotlin INSTANCE;
public final String getName() {
return name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "");
name = var1;
}
public final void speak() {
}
static {
BookKotlin var0 = new BookKotlin();
INSTANCE = var0;
name = "AA";
}
}
虽然 name 是 static 的了,但还是 private 私有的,还是得通过静态单例来中转调用,真的是单例
const
const 写在 class 外面,效果 = @JvmField,但是不能修饰方法,也不能和 @JvmField 混用,一般就是用来声明常用值的,用处不多,而且只能用 val ,var 不行,想要修饰方法的话,不写 const 就行
const val name: String = "AA"
fun adk(){}
class BookKotlin {
fun speak() {}
}
kotlin 中使用如下:
kotlin 没有包的概念,所以直接用,注意这么写其实已经相当于脱离了类的范围,一个包的范围内不能重名的
java 中使用如下:
这个 BookKotlinKt 文件就是为了专门支持这个 kotlin 特性而生成的辅助类,java 中我们是通过这个类来调用 const 声明的内容的,为啥要有这个类呢,因为 java 是有包这个概念的,所有的文件必须要有统一的地址规范,所以 kotlin 层面只能是提供 XXXKt 文件来单独支持了,其实这已经脱离了 java 范围
把 kotlin 代码转成 java:
public final class BookKotlin {
public final void speak() {
}
}
public final class BookKotlinKt {
@NotNull
public static final String name = "AA";
public static final void adk() {
}
}
在 java 代码中是以 kotlin 辅助类存在的,这样用的人真的是非常少,限制太大