对象声明(单例)
定义一个类并创建它的实例。可以继承类实现接口、包含属性和方法,但是不能手动声明构造。
?Kotlin声明:可以声明在顶层、也可以声明在类中(见下方和伴生对象对比)
object Demo{
val name = "单例"
fun show() = println(name)
}
Demo.show()
println(Demo.name)
反编译成Java代码:
public final class Demo {
//成员变量
private static String name;
//通过静态字段提供实例
public static final Demo INSTANCE;
//私有化构造
private Demo() { }
//静态代码块中初始化
static {
Demo var0 = new Demo();
INSTANCE = var0;
name = "单例";
}
//成员方法
public final void show() {
String var1 = name;
System.out.println(var1);
}
//生成的getter、setter
public final String getName() { return name; }
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
name = var1;
}
}
?模仿Java方式写Kotlin带参数单例:
class Demo private constructor(
private var id: Long,
private var name: String
) {
companion object {
private var instance: Demo? = null
fun getInstance(id: Long, name: String) {
instance ?: synchronized(this) {
instance ?: Demo(id, name).also { instance = it }
}
}
}
}
伴生对象(static静态、工厂模式)
- 伴随着类而存在的对象,在类加载的时候初始化。Kotlin 中没有 static 静态的概念,可以使用顶层函数和常量。顶层函数不能访问类中私有的成员,在伴生对象中需要用外部实例来访问(静态内部类无法直接访问外部类中的非静态成员),Outter().num。
- 当类中成员和伴生对象中成员重名的时候,类名调用的是伴生对象中的,实例调用的是类中的。
| 伴生对象 | 类中单例对象声明 | 相同 | 都是一个静态内部类,通过(外部类名.内部类名.成员名)的方式调用。 构造都是 private 都可以继承类、实现接口、拥有属性和函数 | 不同 | ①外部类中创建并持有伴生对象的实例 ②定义的属性会成为外部类的私有静态字段,声明private便不会。函数还留在内部 ③一个类中只能拥有一个伴生对象 | ①自己就是实例 ②持有自己的属性和函数 ③一个类中可以拥有多个单例对象 |
Kotlin声明:伴生对象和类中的单例
class Demo {
//伴生对象
companion object AA{ //不取名的话,默认名称是 Companion
var a = 1
fun aa() = println("伴生对象")
}
//单例
object BB {
var b = 2 //可以自定义getter、setter
fun bb() = println("单例")
}
}
?反编译成Java代码:
public final class Demo {
//伴生对象中的成员变量(外部类持有)
private static int a = 1;
//持有伴生对象实例(外部类持有)
public static final Demo.AA AA = new Demo.AA((DefaultConstructorMarker)null);
//伴生对象
public static final class AA {
//私有化构造
private AA() { }
// $FF: synthetic method 合成的方法
public AA(DefaultConstructorMarker $constructor_marker) {
this();
}
//成员方法
public final void aa() {
String var1 = "伴生对象";
System.out.println(var1);
}
//生成的getter、setter
public final int getA() { return Demo.a; }
public final void setA(int var1) { Demo.a = var1; }
}
//单例
public static final class BB {
//通过静态字段提供实例
public static final Demo.BB INSTANCE;
//私有化构造
private BB() { }
//静态代码块中初始化
static {
Demo.BB var0 = new Demo.BB();
INSTANCE = var0;
b = 2;
}
//成员变量
private static int b;
//成员方法
public final void bb() {
String var1 = "单例";
System.out.println(var1);
}
//生成的getter、setter
public final int getB() { return b; }
public final void setB(int var1) { b = var1; }
}
}
静态工厂:
interface Car {
val brand: String
companion object {
operator fun invoke(type: CarType): Car {
return when (type) {
CarType.AUDI -> Audi()
CarType.BMW -> BMW()
}
}
}
}
Car(CarType.BMW)
扩展方法:虽然是在伴生对象上扩展,实际相当于给外部类增加了静态方法。
fun Outter.Companion.show(){}
Outter.show()
对象表达式(匿名内部类)
不像 Java 的匿名内部类只能单继承/单实现,Kotlin 匿名对象可以一次搞定多个接口/抽象类,访问外部局部变量也不用加 final。一般使用 Lambda 更便捷,当需要重写多个方法时,只能选择匿名对象了。
xxx.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View){...}
})
xxx.setOnClickListener{ view -> ... }
interface AA{ fun aa() }
interface BB{ fun bb() }
fun method(param:AA){ param.aa() }
//调用
method(object : AA,BB {
override fun aa() {...}
override fun bb() {...}
})
|