单例对象与类中的伴随对象

时间:2018-05-25 07:30:45

标签: scala

我写了以下代码:

class a {

  object c {
    var a = "STATIC"

    def m() = print("STATIC METHOD")

    var f = () => print("STATIC FUNCTION")
  }

}

object m {
  def main(args: Array[String]) = {
    var o = new a()
    o.c.m()
  }
}
  1. 我可以说对象c中声明的变量,函数和方法可以是静态的吗?
  2. 如果我用c更改对象a的名称,那么该对象会成为伴侣对象吗?

3 个答案:

答案 0 :(得分:3)

object中的字段和方法是Scala如何在Java中声明您将使用static的内容。我想你可以直觉地说那些字段通常是static(就像在中只有一个JVM中的一个)。

但是,在您的示例中,您在类中放置了object,使其不再是 static 。您可以使用几行代码轻松检查(您可以找到here on Scastie)。

class MyClass {

  object Embedded {
    val a = "field"
    def m = println("method")
  }

}

val a = new MyClass().Embedded
val b = new MyClass().Embedded

// prints "a and b are different objects"
if (a eq b)
  println("a and b are the same object")
else  
  println("a and b are different objects")

关于您的第二个问题:不,classobject必须位于同一范围内,才能使其成为伴侣对象。您可以在Scala Language Specification上找到更多详细信息。

我引用那里:

  

通常,类的伴随模块是一个与该类同名的对象,并在同一范围和编译单元中定义。相反,该类被称为模块的伴随类。

答案 1 :(得分:3)

Scala与Java没有“静态”的真正含义。

对象在使用静态方法/字段的JVM上有支持这一事实是一个泄漏的实现细节,如果使用Java / JVM互操作,您只需要处理它。

除非你明确需要这个互操作,否则你需要停止将声明的对象视为'静态',而是将它们视为在给定范围内的单例。

嵌套在类下的内部对象意味着对于每个类实例,只有1个实例,不同于可能有多个实例的内部类。

这也适用于顶级,除了Scala可以与其他JVM语言进行额外兼容,并将某些方法/成员标记为静态。

答案 2 :(得分:2)

回答你的问题:

  1. a.c中的方法和字段不是全局静态的,因为它们需要存在a的实例。如果a是对象,a.c也是静态的。

  2. 如果您想要一个包含静态字段和方法的伴随对象a,则必须在a的代码块之外定义它,如下所示:

    class a {
      /* non-static stuff goes here */
    }
    object a {
      /* static stuff goes there */
      def m() = print("STATIC METHOD")
    }
    
  3. 您必须将两者保存在同一个文件中,定义对象或 class first无关紧要,因此它通常取决于约定或根据用例最有意义。 如果您想在a.m内调用静态方法class a,则仍需要将其称为a.m,而不仅仅是m。但是class a将能够使用object a的私有字段和方法,因为它们是同伴。

    正如其他人已经说过的那样,static在Scala中并不存在,但是这个概念来自Java,因为Scala在大多数情况下被编译成java字节码。

    最后的建议,Scala和Java中的类和对象的约定通常是相同的:它们的名字的第一个字母应该是大写的(除了一些高级的Scala案例)