Scala中的"new"关键字

109
我有一个非常简单的问题 - 在Scala中创建对象时,何时应该使用new关键字?只有在实例化Java对象时才需要吗?
3个回答

157

在想要引用一个类自己的构造函数时,使用new关键字:

class Foo { }

val f = new Foo

如果你想引用伴生对象的 apply 方法,则可以省略 new

class Foo { }
object Foo {
    def apply() = new Foo
}

// Both of these are legal
val f = Foo()
val f2 = new Foo
如果您创建了一个 case class:
case class Foo()

Scala会为你偷偷地创建一个伴生对象,这会变成这样:

class Foo { }
object Foo {
    def apply() = new Foo
}

所以你可以这样做

f = Foo()

最后,请记住并不是所有的规则都说伴随apply方法必须是构造函数的代理函数:

class Foo { }
object Foo {
    def apply() = 7
}

// These do different things
> println(new Foo)
test@5c79cc94
> println(Foo())
7

而且,既然你提到了Java类:是的 - Java类很少有伴生对象,其中包含一个apply方法,因此您必须使用new和实际类的构造函数。


1
一个 Java 类永远不可能有伴生对象。它可以有一个对象,可以作为 Java 类的工厂使用 - 但是这个对象不是它的伴生对象。 - kiritsuku
@Antoras 由于Scala类编译成Java字节码,并且可以以编译形式分发,Scala能否区分实际的Scala伴生对象和一个名为Foo$的类,其中包含一个静态MODULE$成员? - Owen
1
我认为scalac可以区分这一点,因为规定伴生对象必须在与其伴生类相同的文件中声明。由于伴生“属性”仅存在于Scala而不是字节码级别上,因此scalac必须检查Scala代码而不是字节码,以确保遵循规范。 - kiritsuku
1
有没有在Scala中不使用new关键字的Java类的示例? - Bober02
此外,伴生对象上的方法也将通过类上的静态方法进行访问,而对于稍后定义“伴生”的Java类来说,这是不可能发生的。 - drexin
非常全面的主题描述!这应该是任何Scala课程的一部分 :-) - matanster

16

这只发生在我们尝试实例化Java对象时吗?

完全不是。在Scala中有两种常见的情况可以省略new关键字。 对于单例对象(通常用于存储静态函数并作为工厂类似于Java中的用法):

scala> object LonelyGuy { def mood = "sad" }
defined module LonelyGuy

scala> LonelyGuy
res0: LonelyGuy.type = LonelyGuy$@3449a8

scala> LonelyGuy.mood
res4: java.lang.String = sad

通过使用case类(实际上,在底层是类+对象= 伴生模式,例如使用相同名称的类和对象):

scala> case class Foo(bar: String) 
defined class Foo


scala> Foo("baz")
res2: Foo = Foo(baz)

所以,当你使用简单的类时,规则与Java相同。

scala> class Foo(val bar: String) 
defined class Foo

scala> new Foo("baz")
res0: Foo = Foo@2ad6a0

// will be a error 
scala> Foo("baz")
<console>:8: error: not found: value Foo
       Foo("baz")

额外福利,Scala 中有匿名类,可以这样构造:

scala> new { val bar = "baz" }
res2: java.lang.Object{val bar: java.lang.String} = $anon$1@10ee5b8

scala> res2.bar
res3: java.lang.String = baz

2
你还好吗,伙计? - Jacob B

3
这是指我们仅在实例化Java对象时才需要使用吗?
通过基于Dotty的Scala 3(应该于2020年中发布,八年后),永远不需要使用“new”,正如这个线程中所述。
创作者应用程序允许使用简单的函数调用语法来创建类的实例,即使没有实现apply方法也可以创建。例如:
class StringBuilder(s: String) {
   def this() = this(s)
}

StringBuilder("abc")  // same as new StringBuilder("abc")
StringBuilder()       // same as new StringBuilder()

创造者应用程序将迄今仅适用于 case 类的功能进行了泛化,但实现机制略有不同。
我们并非使用自动生成的 apply 方法,而是为函数调用 f(args) 添加了一种新的可能解释。

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