Scala - new vs object extends



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

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

实际上,object声明的初始化机制与字节码中的new相同。但是,存在很多差异:

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

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

* 什么是"相关"类或特征是一个更长的故事 - 如果你有兴趣,可以在 Stack Overflow 上查找解释它的问题。如果您在查找 wiki 时找不到 scala 标签,请查看它们。

对象定义(无论它是否扩展某些内容(意味着单例对象创建。

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

虽然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,而test2 b定义为扩展Fooobject。从本质上讲,两者都懒惰地创建一个新的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也是如此。我能想到的主要实际区别是对象具有更具体的静态类型:b 属于 b.type 类型(扩展Foo(,而 a 的类型正是 Foo

最新更新