美文网首页
Kotlin与Java比较:对象

Kotlin与Java比较:对象

作者: 程序引力 | 来源:发表于2018-12-06 23:52 被阅读28次

    前言

    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 静态初始化器的语义相匹配。

    相关文章

      网友评论

          本文标题:Kotlin与Java比较:对象

          本文链接:https://www.haomeiwen.com/subject/uesgcqtx.html