一、将 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 的文件专门对齐提供支持
1、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 中调用成员方法和属性
看上面图,我们在 kotlin 中使用时感觉的确是和 java 中的 static 一样,静态参数方法和成员参数方法能有效区别开来,下面我们来看看 java 中使用
类名. 没有静态属性和方法,只有一个静态对象
这个静态对象下我们可以找到我们声明的静态属性和方法
new 一个对象我们可以使用成员变量和方法
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 代码来一探究竟
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, "<set-?>");
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, "<set-?>");
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 特性
2、@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() {}
}
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, "<set-?>");
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();
}
}
}
3、object 单例
kotlin 自身提供了一种单例实现方式:object ,直接用来修饰 class ,用 object 修饰的类不能 new 对象,只能使用 object 提供的单例
object BookKotlin {
var name: String = "AA"
fun speak() {}
}
object 修饰的类不能创建对象了
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, "<set-?>");
name = var1;
}
public final void speak() {
}
static {
BookKotlin var0 = new BookKotlin();
INSTANCE = var0;
name = "AA";
}
}
虽然 name 是 static 的了,但还是 private 私有的,还是得通过静态单例来中转调用,真的是单例
4、const
const 写在 class 外面,效果 = @JvmField,但是不能修饰方法,也不能和 @JvmField 混用,一般就是用来声明常用值的,用处不多,而且只能用 val ,var 不行,想要修饰方法的话,不写 const 就行
const val name: String = "AA"
fun adk(){}
class BookKotlin {
fun speak() {}
}
kotlin 中使用如下:
kotlin 没有包的概念,所以直接用,注意这么写其实已经相当于脱离了类的范围,一个包的范围内不能重名的
这个 BookKotlinKt 文件就是为了专门支持这个 kotlin 特性而生成的辅助类,java 中我们是通过这个类来调用 const 声明的内容的,为啥要有这个类呢,因为 java 是有包这个概念的,所有的文件必须要有统一的地址规范,所以 kotlin 层面只能是提供 XXXKt 文件来单独支持了,其实这已经脱离了 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 辅助类存在的,这样用的人真的是非常少,限制太大