文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Kotlinobject的几种用法示例详解

2022-12-08 20:57

关注

1.object:匿名内部类

在Android最常用的匿名内部类之一就是点击事件,用Java语言写的话就是下面这样:

public interface OnClickListener {
    void onClick(View v);
}
button.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v){
    }
});

上面的代码在Kotlin中就要这么写

interface OnClickListener {
    fun onClick(v: View)
}
button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View) {
    }
})

上面的代码中object: View.OnClickListener就是匿名内部类的使用方式。

这里的代码为了说明【object: 匿名内部类】的用法所以写的比较啰嗦,如果用Lambda写法的话可以这么写

button.setOnClickListener {
}

上面是匿名内部类常用的一种方式,还有另一种用法就是:在继承一个抽象类的同时还可以实现多个接口,直接看代码:

interface Behavior {
    fun sleep()
}
interface Characteristics {
    fun gender()
}
abstract class Person {
    abstract fun walk()
}
fun main() {
    // 这个匿名内部类,在继承了Person类的同时,还实现了Behavior(行为)、Characteristics(特征)两个接口
    val item = object : Person(), Behavior, Characteristics {
        override fun sleep() {
        }
        override fun gender() {
        }
        override fun walk() {
        }
    }
}

对上面的代码说明:在继承了Person类的同时,还实现了Behavior(行为)、Characteristics(特征)两个接口并分别重写了他们的方法,这种用法灵活性比较高。

2.object: 伴生对象

Kotlin 当中没有 static 关键字,所以我们没有办法直接定义静态方法和静态变量。不过,Kotlin 还是为我们提供了伴生对象,来帮助实现静态方法和变量。

先看一种嵌套类的特殊情况

class Person {
    object InnerSingleton {
        fun foo() {}
    }
}
//反编译后的Java代码
public final class Person {
    public static final class InnerSingleton {
        @NotNull
        public static final Person.InnerSingleton INSTANCE;
        public final void foo() {
        }
        private InnerSingleton() {
        }
        static {
            Person.InnerSingleton var0 = new Person.InnerSingleton();
            INSTANCE = var0;
        }
    }
}

由以上代码可知定义的foo方法并不是一个静态方法,那要如何实现这个静态方法呢,可以foo方法上面加入注解@JvmStatic,这样反编译后foo方法就是一个静态方法了

class Person {
    object InnerSingleton {
        @JvmStatic
        fun foo() {}
    }
}
//反编译后的Java代码
public final class Person {
    public static final class InnerSingleton {
        @NotNull
        public static final Person.InnerSingleton INSTANCE;
        @JvmStatic
        public static final void foo() {
        }
        private InnerSingleton() {
        }
        static {
            Person.InnerSingleton var0 = new Person.InnerSingleton();
            INSTANCE = var0;
        }
    }
}

经过这么改动Kotlin和Java的实现方式就都可以这么写

Person.InnerSingleton.foo()

此时还有一个问题,foo方法的InnerSingleton有点多余,它并没有实际意义,想直接调用Person.foo()要怎么做?

object前面加入一个companion关键字即可

//Kotlin代码
class Person {
    companion object InnerSingleton {
        @JvmStatic
        fun foo() {
        }
    }
}
//反编译后的代码
public final class Person {
    @NotNull
    public static final Person.InnerSingleton InnerSingleton = new Person.InnerSingleton((DefaultConstructorMarker)null);
    @JvmStatic
    public static final void foo() {
        InnerSingleton.foo();
    }
    public static final class InnerSingleton {
        @JvmStatic
        public final void foo() {
        }
        private InnerSingleton() {
        }
        // $FF: synthetic method
        public InnerSingleton(DefaultConstructorMarker $constructor_marker) {
            this();
        }
    }
}

加入companion就实现了Person.foo()的调用。companion object就是Kotlin中的伴生对象, 它其实是嵌套单例的一种也是情况。

通过上面的代码可以得出一个结论:当伴生对象存在时如果还存在

@JvmStatic修饰的方法或者属性,那么Kotlin编译成Java代码后它就会被挪到外部的类中变成静态成员。嵌套单例是

object单例的一种特殊情况,伴身对象是嵌套单例的一种特殊情况。

3.单例模式

Kotlin中定义一个普通的单例模式非常简单只需要在类名前面用object声明即可

object Utils{
}

这样就能实现单例,但是Java中的单例是比较复杂的,并且还有懒汉式和饿汉式之分,这样真的就能定义吗?

我们看一下这段代码反编译成Java的代码看一看就很清楚了:

public final class Utils {
    @NotNull
    public static final Utils INSTANCE;
    private Utils() {
    }
    static {
        Utils var0 = new Utils();
        INSTANCE = var0;
    }
}

static中的代码由虚拟机决定只会运行一次,同时在保证线程安全的前提下也保证了INSTANCE只运行一次。

但是这里有2个缺陷:

那要如何解决?

class Person(val name: String) {
}
fun main() {
    val user by lazy { Person("张三") }
    println("user is name ${user.name}")
}

上面的代码使用了by lazy{ }创建了Person对象,而Person对象最终创建的时机是在println创建的,也就是说懒加载委托的特点就是只有在使用这个对象是才会创建实例。

直接看代码,代码是从《朱凯·Kotlin编程第一课》直接拷贝过来的

class UserManager private constructor(name: String) {
    companion object {
        @Volatile
        private var INSTANCE: UserManager? = null
        fun getInstance(name: String): UserManager =
        // 第一次判空
        INSTANCE ?: synchronized(this) {
            // 第二次判空
            INSTANCE ?: UserManager(name).also { INSTANCE = it }
        }
    }
}
fun main() {
    // 使用
    UserManager.getInstance("Tom")
}

这里首先定义了一个INSTANCE并且用private修饰这样就可以保证不能被外界直接访问,同时添加了@Volatile注解可以保证INSTANCE的可见性,而 getInstance() 方法当中的 synchronized,保证了 INSTANCE 的原子性。因此,这种方案还是线程安全的。

另外还要注意的一点是初始化定义的INSTANCE的默认值时null你这也就保证了只有在使用它的时候才会被实例化,也就是说实现懒加载的模式。

这中实现方式也是可以传参的,在getInstance()方法中定义需要的属性即可实现传参

这个代码其实跟Java的懒汉模式 + synchronized 同步锁非常相似

public class UserManager {
    private static volatile UserManager mInstance = null;
    private UserManager() {
    }
    public static UserManager getInstance() {
        if (mInstance == null) {
            synchronized (UserManager.class) {
                if (mInstance == null) {
                    mInstance = new UserManager();
                }
            }
        }
        return mInstance;
    }
}

上面介绍了3中单例模式的实现方式,他们的使用场景如下:

以上就是Kotlin object的几种用法示例详解的详细内容,更多关于Kotlin object用法示例的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯