【问题标题】:Scala - new vs object extendsScala - 新对象与对象扩展
【发布时间】:2013-04-24 03:13:16
【问题描述】:

使用 new 运算符定义对象与通过扩展类定义独立对象有什么区别?

更具体地说,给定类型class GenericType { ... }val a = new GenericTypeobject a extends GenericType 有什么区别?

【问题讨论】:

标签: scala


【解决方案1】:

实际上,object 声明的初始化机制与字节码中的new 相同。不过还是有不少区别的:

  • object 作为单例——每个都属于一个只存在一个实例的类;
  • object 被延迟初始化——它们只会在第一次被引用时被创建/初始化;
  • objectclass(或trait)是同伴
  • object 上定义的方法在同伴class 上生成静态转发器;
  • object 的成员可以访问同伴 class 的私有成员;
  • 在搜索隐式时,会查看相关* 类或特征的伴随对象。

这些只是我能想到的蝙蝠的一些差异。可能还有其他人。

* 什么是“相关”类或特征是一个较长的故事——如果您有兴趣,请查看 Stack Overflow 上的问题来解释它。如果您找不到它们,请查看 wiki 中的 scala 标签。

【讨论】:

    【解决方案2】:

    对象定义(无论它是否扩展了某些东西)意味着创建单例对象。

    scala> class GenericType
    defined class GenericType
    
    scala> val a = new GenericType
    a: GenericType = GenericType@2d581156
    
    scala> val a = new GenericType
    a: GenericType = GenericType@71e7c512
    
    scala> object genericObject extends GenericType
    defined module genericObject
    
    scala> val a = genericObject
    a: genericObject.type = genericObject$@5549fe36
    
    scala> val a = genericObject
    a: genericObject.type = genericObject$@5549fe36
    

    【讨论】:

      【解决方案3】:

      虽然object 声明与new 表达式具有不同的语义,但本地object 声明的所有意图和目的都与同名的lazy val 相同。考虑:

      class Foo( name: String ) {
        println(name+".new")
        def doSomething( arg: Int ) {
          println(name+".doSomething("+arg+")")
        }
      }
      
      def bar( x: => Foo ) {
        x.doSomething(1)
        x.doSomething(2)
      }
      
      def test1() {
        lazy val a = new Foo("a")
        bar( a )
      }
      
      def test2() {
        object b extends Foo("b")
        bar( b )
      }
      

      test1a 定义为使用Foo 的新实例初始化的惰性val,而test2b 定义为object 扩展Foo。 本质上,两者都是懒惰地创建Foo 的新实例并为其命名(a/b)。

      您可以在 REPL 中尝试并验证它们的行为是否相同:

      scala> test1()
      a.new
      a.doSomething(1)
      a.doSomething(2)
      
      scala> test2()
      b.new
      b.doSomething(1)
      b.doSomething(2)
      

      因此,尽管 objectlazy val 之间存在语义差异(特别是语言对 object 的特殊处理,如 Daniel C. Sobral 所述), lazy val 总是可以用相应的 object 替换(并不是说这是一个非常好的做法),同样适用于作为类/特征成员的 lazy val/object。 我能想到的主要实际区别是对象有一个更具体的静态类型:bb.type 类型(扩展 Foo),而 a 正好是 Foo 类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-30
        • 1970-01-01
        • 2014-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多