对象表达式
对象表达式相当于Java中的匿名类,实现方式是 object: 后跟要实现的类或接口
open class Person {
}
fun main() {
object: Person() {
}
}
对于只使用一次的类实例来说,这还是很方便的,这个例子反编译之后是这样的
public final class ObjectDemoKt {
public static final void main() {
new Person() {
};
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
可以发现,这和Java中实现匿名类是一样的。
对象声明
一般情况下我们使用Class关键字声明一个类,然后再实例化类的对象,对象声明则是使用object 关键字直接声明一个对象,它的作用相当于Java中的单例类。
object DataManager {
private const val TAG = "DataManager"
val data: String? = null
fun parseData() {
}
}
咱们创建了一个对象声明DataManager,它有一个const常量,一个常量和一个方法,对象声明不允许有构造方法,这个对象声明反编译为Java代码是这样的
public final class DataManager {
private static final String TAG = "DataManager";
@Nullable
private static final String data;
@NotNull
public static final DataManager INSTANCE;
@Nullable
public final String getData() {
return data;
}
public final void parseData() {
}
private DataManager() {
}
static {
DataManager var0 = new DataManager();
INSTANCE = var0;
}
}
可以看到常量都变为static的了,同时在static代码块中创建了类的实例,我们都知道static代码块在类加载的时候就会调用,在Kotlin中对它进行方法调用,反编译之后是这样的
DataManager.data
DataManager.parseData()
DataManager.INSTANCE.getData();
DataManager.INSTANCE.parseData();
如果此时在Java中调用此对象声明,会发现最终效果是这样的
DataManager.INSTANCE.parseData();
并不是我们想象的直接调用
DataManager.parseData()
此时就需要用到@JvmStatic,详情请参考从Java调用Kotlin代码
伴生对象
把对象声明放在一个类内部,并且用companion修饰,就是伴生对象,此处可以省略对象名称。
class MyClass {
private val count = 3
companion object Custom {
private const val name = ""
fun create(): MyClass = MyClass()
fun getCount(): Int {
TODO()
}
}
fun getName(): String {
return name
}
}
外部类可以直接访问伴生对象的变量,调用create方法时是这样的
val instance = MyClass.create()
把MyClass反编译为Java之后是这样的
public final class MyClass {
private final int count = 3;
private static final String name = "";
@NotNull
public static final Custom Custom = new Custom((DefaultConstructorMarker)null);
@NotNull
public final String getName() {
return "";
}
public static final class Custom {
@NotNull
public final MyClass create() {
return new MyClass();
}
public final int getCount() {
throw new NotImplementedError((String)null, 1, (DefaultConstructorMarker)null);
}
private Custom() {
}
// $FF: synthetic method
public Custom(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
可以看到伴生对象成了外部类的静态内部类,伴生对象的常量成了外部类的静态常量。
工具类
Java中我们会经常用到工具类,在Kotlin中应该怎么定义工具类呢?
class DataUtil {
companion object {
fun parseData() {
}
}
}
object DataManager {
private const val TAG = "DataManager"
val data: String? = null
fun parseData() {
}
}
通过使用伴生对象和对象声明,我们可以实现和Java中工具类同样的效果,通过类名直接调用。
单例
- 通过对象声明可以实现单例
object StringUtil {
init {
println()
}
fun changeTo(value: String) {
}
}
StringUtil.changeTo("")
这种创建单例的方式比较简单,而且是线程安全的,它在类加载时就创建了对象实例。
- 使用伴生对象和内部对象声明
class MySingleton private constructor() {
companion object {
fun getInstance(): MySingleton {
return Holder.instance
}
}
private object Holder {
val instance = MySingleton()
}
}
- 采用同步锁的方式
class Singleton private constructor() {
companion object {
private var instance: Singleton? = null
@Synchronized
fun getInstance(): Singleton? {
if (instance == null) {
instance = Singleton()
}
return instance
}
}
}
- 懒汉同步块式
class Custom private constructor() {
companion object {
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
Custom()
}
}
}
参考: