object使用来声明对象的,可以声明以下三种对象。
- 生成匿名类(匿名object)
- 对象声明(命名object)
- 伴生对象
对象表达式(匿名object对象)
使用object可以有如下几种用法
- 只生成一个简单对象
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
复制代码
- 继承某些类生成匿名对象
class A{
var t : A0? = null;
fun setListener(a:A0){
t = a
}
}
open class A0{
fun doSome(){
print("some");
}
}
fun test(){
A().setListener(object :A0(){})
}
复制代码
一些重要的特性
- 能够实现多继承的匿名类。
open class A(x: Int) {
public open val y: Int = x
}
interface B { /*……*/ }
val ab: A = object : A(1), B {
override val y = 15
}
复制代码
- 对象表达式中的代码可以访问来自包含它的作用域的变量
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
}
复制代码
匿名对象会在使用的时候立即初始化。
对象声明(命名object对象)
在object关键字后面跟一个名字,就声明了一个对象,我把这叫object 命名对象,比如
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
//调用
DataProviderManager.registerDataProvider(……)
复制代码
object 命名对象可以有超类。但是不可以在局部作用域中生成。
命名对象会延迟访问,会在第一次被访问到时才被初始化(这是官网的话)。
我把kt文件转成java之后时在static{}中初始化的。如果时这样因该是时类加载时初始化
companion 对象
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
复制代码
onpanion 是在类加载解析的时候就开始初始化。
转换成java之后
简单对象对应的java代码
public static final void foo() {
<undefinedtype> adHoc = new Object() {
private int x;
private int y;
public final int getX() {
return this.x;
}
public final void setX(int var1) {
this.x = var1;
}
public final int getY() {
return this.y;
}
public final void setY(int var1) {
this.y = var1;
}
};
int var1 = ((<undefinedtype>)adHoc).getX() + ((<undefinedtype>)adHoc).getY();
System.out.print(var1);
}
复制代码
可以看到 foo()方发是静态的,并且用了object方法来包装了对象。
有继承的匿名类转换后。直接包object 声明的匿名对象转换成了对应的对象,并且也把调用方法转化成了静态的。
//其他的类方法没有发生变化。
public static final void test() {
(new A()).setListener((A0)(new A0() {
}));
}
复制代码
继承结构的命名object
public final class DefaultListener extends MouseAdapter {
public static final DefaultListener INSTANCE;
public void mouseClicked(@NotNull MouseEvent e) {
Intrinsics.checkParameterIsNotNull(e, "e");
}
public void mouseEntered(@NotNull MouseEvent e) {
Intrinsics.checkParameterIsNotNull(e, "e");
}
static {
DefaultListener var0 = new DefaultListener();
INSTANCE = var0;
}
}
复制代码
将类变成final类型的,且在代码块中初始化了这个对象。这个应该时类加载的时候初始化。
public final class MyClass {
public static final MyClass.Factory Factory = new MyClass.Factory((DefaultConstructorMarker)null);
public static final class Factory {
@NotNull
public final MyClass create() {
return new MyClass();
}
private Factory() {
}
// $FF: synthetic method
public Factory(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
复制代码
可以看到这里使用了一个静态内部类+静态变量实现的单例。
Factor是一个静态的容器类,里面方法返回对象,外层利用静态变量初始化的特性调用内部容器生成对象。
这个设计主要是基于jvm在加载外部类的过程中是不会加载静态内部类。只有内部类的属性和方法被调用时才会被加载。开始初始化静态属性。有点事延迟加载,而且没有线程安全问题。这种做法在开源项目中比常见。
重点
- 匿名类(匿名object):在使用他们的地方立即执行,普通的初始化。
- 对象声明(命名object):延迟初始化,第一次使用时才开始初始化。(反编译为java之后发现时在static{}代码块中初始化的,估计时编译器有做特殊处理了,有点矛盾第一次使用才初始化和普通的类没区别了)
- companion object 类加载之后就开始出化
针对对象声明(命名object对象)初始化问题,如果有朋友知道麻烦告知一下。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END