其他
Kotlin Vocabulary | 唯一的 "对象"
什么是单例?
单例是一种设计模式,它保证一个类只有唯一一个实例,并且提供全局可访问该对象的接口。单例非常适合那些需要在应用的不同地方共享的对象,以及初始化实例非常消耗资源的场景下使用。
Java 中的单例
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
public class Singleton{
private static Singleton INSTANCE;
private Singleton(){}
public static Singleton getInstance(){
if (INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
private int count = 0;
public int count(){ return count++; }
}
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
public class Singleton{
private static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
if (INSTANCE == null) { // 一次检查
synchronized (Singleton.class) {
if (INSTANCE == null) { // 二次检查
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
private int count = 0;
public int count(){ return count++; }
}
Kotlin 中的单例
那么我们再来看看 Kotlin。Kotlin 中并没有静态方法或者静态字段,那么我们如何在 Kotlin 中创建单例呢?
实际上,可以通过 Android Studio/IntelliJ 来帮助我们理解这一问题。当您将 Java 的单例代码转换为 Kotlin 代码时,所有的静态属性和方法就会被移动到 companion object 中。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class Singleton private constructor() {
private var count = 0
fun count(): Int {
return count++
}
companion object {
private var INSTANCE: Singleton? =
Singleton()//二次检查
// Single Checked
val instance: Singleton?
get() {
if (INSTANCE == null) { //首次检查
synchronized(Singleton::class.java) {
if (INSTANCE == null) { //二次检查
INSTANCE =
Singleton()
}
}
}
return INSTANCE
}
}
}
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
object Singleton {
private var count: Int = 0
fun count() {
count++
}
}
如果想查看一个 Kotlin 类的字节码,依次选择 Tools > Kotlin > Show Kotlin Bytecode。Kotlin 字节码显示以后,点击 Decompile 来查看反编译的 Java 代码。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
public final class Singleton {
private static int count;
public static final Singleton INSTANCE;
public final int getCount() {return count;}
public final void setCount(int var1) {count = var1;}
public final int count() {
int var1 = count++;
return var1;
}
private Singleton() {}
static {
Singleton var0 = new Singleton();
INSTANCE = var0;
}
}
⚠️ 和其它静态方法一样,静态的初始化代码块只能访问一个类的静态属性。静态的代码块的调用要早于构造方法,所以静态代码块无法访问对象的属性或者传递给构造函数的参数。
companion object
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class SomeClass {
//…
companion object {
private var count: Int = 0
fun count() {
count++
}
}
}
class AnotherClass {
//…
companion object Counter {
private var count: Int = 0
fun count() {
count++
}
}
}
//不定义名称的场景
SomeClass.count()
//定义名称的场景
AnotherClass.Counter.count()
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
public final class AnotherClass {
private static int count;
public static final AnotherClass.Counter Counter = new AnotherClass.Counter((DefaultConstructorMarker)null);
public static final class Counter {
public final void count() {
AnotherClass.count = AnotherClass.count + 1;
}
private Counter() { }
// $FF: synthetic method
public Counter(DefaultConstructorMarker $constructor_marker) {
this();
}
}
public static final class Companion {
public final void count() {
AnotherClass.count = AnotherClass.count + 1;
}
private Companion() {}
}
}
Object 表达式
到目前为止,我们已经在声明对象的时候使用了 object 关键字,不过它也可以用于 object 表达式。当作为表达式使用时,object 关键字可以帮助您创建匿名对象和匿名内部类。
比如您需要一个临时对象来保持一些数据值时,可以立即声明对象并使用所需的数值进行初始化,之后再访问它们。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
val tempValues = object : {
var value = 2
var anotherValue = 3
var someOtherValue = 4
}
tempValues.value += tempValues.anotherValue
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<undefinedtype> tempValues = new Object() {
private int value = 2;
private int anotherValue = 3;
private int someOtherValue = 4;
// x,y,z 的 getter 和 setter
//...
};
object 关键字无需使用模板代码就可以创建匿名类。您可以使用 object 表达式,而 Kotlin 编译器则会生成包裹类的声明来创建一个匿名类。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
//Kotlin 代码
val t1 = Thread(object : Runnable {
override fun run() {
// 逻辑代码
}
})
t1.start()
//反编译的 Java 代码
Thread t1 = new Thread((Runnable)(new Runnable() {
public void run() {
}
}));
t1.start();
推荐阅读