Kotlin与Java比较:对象

前言

Kotlin作为JVM系的语言,起源于Java又不同于Java。通过在语言层面比较两者的区别,可以使得开发者能够快速学习,融会贯通。

匿名对象

有时需要对某个类做轻微的改动并获取它的对象,Kotlin与Java提供了不同的支持。

  • Java
    在Java中提供了匿名内部类对这一需求的支持,即在初始化类的地方覆写基类的实现。
class Person
{
    public void show()
    {
        System.out.println(“Person”);
    }
}

class Main{
    public void test(new Person(){    //匿名内部类
          @override
          show(){
              //xxx
          }
    });
}

匿名内部类首先是内部类,是在类中定义的类,同时匿名表示没有名字,直接覆盖其实现后new出来的。匿名内部类的使用非常广泛,特别是那种需要修改某一个类的实现,且只需要这个实现的一个对象的时候。需要注意的是,在Java中,匿名内部类只能访问外部类的final变量。

Kotlin

在Kotlin中与匿名内部类对应的是对象表达式,即通过object关键字去定义与初始化匿名类。其写法结构为:

object : 基类名(主构造函数参数){
      覆盖类的实现
}

例如:

window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { …… }
    override fun mouseEntered(e: MouseEvent) { …… }
})

由于object后仅有基类的名称,故覆盖后的类是没有名字的,即匿名的。

若有多个基类,可以通过逗号分隔:

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 foo() {
    val adHoc = object {
        var x: Int = 0
        var y: Int = 0
    }
    print(adHoc.x + adHoc.y)
}

该匿名对象可以作为私有作用域的对象,也可以作为公有作用域的对象。前者返回的是匿名对象类型,后者返回的是匿名对象声明的基类,若无基类则返回Any类型。

class C {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函数,所以其返回类型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // 没问题
        val x2 = publicFoo().x  // 错误:未能解析的引用“x”
    }
}

单例对象与静态方法

  • Java
    单例即一个类的唯一实例,在Java中为了获得单例常会使用设计模式中的到单例模式来获得单例。
// 一种单例的实现
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){

    }
    public static SingletonDemo getInstance(){
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}

与单例类似的为静态类,但它们也有区别:

  • 单例可以延迟加载或控制,而静态类在被第一次初始化时加载

  • 单例可以被override,而静态类不可以

  • 单例易于被测试

  • 单例与静态类的回收时机不同(待补充)

  • Kotlin
    在Kotlin中为了使用单例或类似于静态类,可以使用对象声明。对象声明相比于对象表达式,在写法上主要是在object后添加了类名,并且不能将该声明放在局部作用域中,但是它们可以嵌套到其他对象声明或非内部类中。其例子为:

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ……
    }
}

// 使用该对象,直接通过类名使用
DataProviderManager.registerDataProvider(……)

若对象声明也有基类,在其名称后添加冒号与基类即可:

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { …… }

    override fun mouseEntered(e: MouseEvent) { …… }
}

对于Kotlin的这一设计,是通过对象声明的名称来对方法进行调用,与Java的静态成员相比,还是略有不同。因为Java是通过外部的类名访问静态成员,而Kotlin的对象声明是通过声明的类名来访问成员。为此,Kotlin还有一个新的概念,即伴生对象。

class NumberTest {
    companion object Obj {  
        var flag = false
        fun plus(x:int, y:int): Int {... }
    }
}

通过在类内部的对象声明前添加companion关键字,即为伴生对象。这个对象是属于外部类的,通过外部类的类名即可调用该对象的成员:

NumberTest.plus(1, 2)    
NumberTest.flag

这就与Java中使用通过类名访问静态成员类似。

对于有名称的伴生对象,可以通过外部类名访问,访问语法为:

//外部类类名.半生对象名.方法
NumberTest.Obj.plus(1, 2)   
//外部类类名.半生对象名.成员
NumberTest.Obj.flag

对于无名称的伴生对象,可以通过外部类名访问,访问语法为:

class NumberTest {
    companion object Obj {  
        var flag = false
        fun plus(x:int, y:int): Int {... }
    }
}

//外部类类名.Companion.方法
NumberTest.Companion.plus(1, 2)   
//外部类类名.Companion名.成员
NumberTest.Companion.flag

注意,伴生对象成员形如Java类中的静态成员,但实际上在运行时它们是真实对象的成员

对象表达式/对象声明/伴生对象的区别

对象表达式和对象声明之间有一个重要的语义差别:

  • 对象表达式是在使用他们的地方立即执行(及初始化)的;
  • 对象声明是在第一次被访问到时延迟初始化的;
  • 伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容