Scala - new vs object extends

7

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

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


可能是 val and object inside a scala class? 的重复问题。 - Bergi
3个回答

10
作为实践问题,object声明与字节码中的new使用相同的机制进行初始化。但是,它们之间存在许多区别:
  • object作为单例——每个对象属于只存在一个实例的类;
  • object被惰性地初始化——只有在第一次引用时才会创建/初始化;
  • 同名的objectclass(或trait)是伴生对象;
  • object上定义的方法会在伴生class上生成静态转发器;
  • object的成员可以访问伴生class的私有成员;
  • 当搜索隐式参数时,将查找相关类或trait的伴生对象。
这些只是我能够立即想到的一些差异。可能还有其他差异。
*“相关”类或trait是一个更长的故事——如果您有兴趣,请查找Stack Overflow上解释它们的问题。如果您找不到它们,请查看scala标签的维基百科页面。

5

对象定义(无论它是否扩展其他对象)意味着单例对象创建。

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

2

虽然 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类的一个新实例。而test2b定义为一个继承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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接