object表达式

很多时候我们想对一个类进行轻微改动(比如重写或实现某个方法),但不想去声明一个子类。在Java里面一般会使用匿名内部类,在Kotlin中使用object关键字来声明匿名类的对象:

Collections.sort(listOf(1), object : Comparator<Int>{
    override fun compare(o1: Int, o2: Int): Int {
        return o1 - o2
    }
}) 

有时候我们只需要一个临时对象,封装一些临时数据,而不想为这个对象单独去定义一个类。object也可以做到:

var obj = object  {
    var x: Int = 0
    var y: Int = 0
}
obj.x = 12
obj.y = 33

在Java中,匿名内部类访问了局部变量会要求这个变量必须是final的,如果后面又需要对这个变量进行更改的话会非常不方便。在Kotlin中则没有这个限制:

fun calculateClickCount(view: View){
    var clickCount = 0 
    view.setOnClickListener(object : OnClickListener{
        override fun onClick(v: View){
            clickCount ++ //可以直接访问和修改局部变量
        }
    })
}

单例声明

单例模式是一种非常有用的设计模式。在Java中实现单例并不是很简单,有时候还要考虑并发问题。成千上万富有智慧的Java程序员创造了多种定义单例的方式,甚至还起了个高大上的名字懒汉式饿汉式;在Java面试题中单例的实现方法出现的频率也非常高。

先看Java中一种典型的饿汉式定义单例的方式:

class HttpClient{
    private HttpClient(){}
    private static HttpClient instance = new HttpClient();
    public static HttpClient getInstance(){
        return instance;
    }
}

好的编程语言会尽可能的帮程序员做事情,解放程序员的心智负担。在Kotlin中定义单例只需要使用object关键字声明即可,无需额外做任何事情:

object HttpClient{
    fun executeRequest(){
        //执行请求   
    }
}
//调用单例对象的方法,虽然看起来像静态调用,但实际上是对象调用
HttpClient.executeRequest()

object声明单例不但简洁,而且线程安全,这一切由Kotlin的编译器技术来保证。如果你感兴趣底层是如何实现的,可以通过Show Kotlin Bytecode查看,会发现原来Kotlin帮我们干了Java版本的实现。

伴生对象

Kotlin中可以使用companion object声明一种特殊的内部类,而且内部类的类名可以省略,这个内部类的对象被称为伴生对象:

class HttpClient {
    //注意:伴生类并不能访问外部类的成员和方法
    companion object {
        fun create(){
        }
    }
}
//调用伴生对象的方法
HttpClient.create()

伴生对象调用方法看起来像单例调用和静态调用,但并不是;还是内部类的实例对象调用。那这有什么卵用呢?

用处就是实现真正的静态调用。

Kotlin中并没有提供直接能进行静态调用的方法,对伴生类的成员和方法添加@JvmStatic注解,就可以实现真正的静态调用:

class HttpClient {
    //注意:伴生类并不能访问外部类的成员和方法
    companion object {
        @JvmStatic var DefaultMethod = "Get"
        @JvmStatic fun create(){
        }
    }
}
//真正的静态变量
HttpClient.DefaultMethod
//真正的静态方法调用
HttpClient.create()

Kotlin为什么没有提供更简洁的静态调用呢?

它肯定可以做到,既然没有提供,我个人猜想是不提倡静态类的编写。因为它提供的单例调用和伴生对象调用在便利性上面和静态调用是一样的,调用者使用起来足够方便,没有必要要求一定是静态的内存分配。

更新时间: 4/30/2019, 9:52:46 PM