问题 具有伴随对象的类与具有相同名称的类和对象之间的区别是什么?


Scala类的“伴随对象”可以被视为单个对象,具有与该类相同的完全限定名称(即同一个名称,在同一个包中)。它们用于保存类的所有实例共有的实用程序函数,以替代Java static 方法。

但是,在文档和问题的不同位置,它表示必须在同一编译单元中定义伴随对象。例如,它们必须在同一个文件中定义; 无法为Java对象定义伴随对象; 在REPL中,它们必须在同一输入行上定义,因此警告信息:

warning: previously defined class Foo is not a companion to object Foo.
Companions must be defined together; you may wish to use :paste mode for this.

这意味着必须区分具有其伴随对象的类,以及具有相同(完全限定)名称的类和对象。这是什么区别?


11008
2017-07-22 22:01


起源



答案:


我们打电话给全班 class SomeClass (虽然它也可能是例如a trait)。

私人会员

伴侣对象的方法(object SomeClass可以访问私有方法/数据 的实例 class SomeClass

如果您的伴随对象仅使用您的类的公共接口(例如,只定义常量),则没有实际区别。但是在许多情况下,让实用程序函数访问私有成员是有用的。例如, object SomeClass 可以定义工厂方法 apply 设立的私人成员 class SomeClass,而不必在公共接口中公开setter。在这种情况下,您必须通过放置定义来定义伴随对象 object SomeClass 在同一个编译单元中 class SomeClass

另一个不同之处在于 编译器在类型的伴随对象(及其超类型)中搜索implicits。因此,如果您使用隐式转换,则在代码中定义 class SomeClass,您必须在伴侣对象中定义它们。

注释

两者的结合也解释了相同的编译单元限制。

  • scalac 无法编译 object SomeClass 直到它知道什么是私人成员 class SomeClass 它叫。
  • scalac 无法编译 class SomeClass 直到它知道它所调用的内容。因此,伴随对象必须不迟于编译 class SomeClass

它遵循它们必须同时编译。此外,当前编译器显然单独编译单独的文件(参见缺少对跨多个文件拆分类的支持),将其限制为相同的编译单元。


16
2017-07-22 22:01



“相同的编译单元”限制不仅仅是编译器的实现细节或部分编译器工程师的懒惰。它也是一种有用的方法来证明你有权访问类的私有成员,即打破封装:如果你可以编辑文件,那么封装已经不在窗口,所以你不会失去任何安全性通过将它们暴露给伴侣对象。如果任何人都可以随时随地定义伴随对象,只需向对象添加一个伴随对象,它们就可以简单地打破对第三方类的封装。 - Jörg W Mittag


答案:


我们打电话给全班 class SomeClass (虽然它也可能是例如a trait)。

私人会员

伴侣对象的方法(object SomeClass可以访问私有方法/数据 的实例 class SomeClass

如果您的伴随对象仅使用您的类的公共接口(例如,只定义常量),则没有实际区别。但是在许多情况下,让实用程序函数访问私有成员是有用的。例如, object SomeClass 可以定义工厂方法 apply 设立的私人成员 class SomeClass,而不必在公共接口中公开setter。在这种情况下,您必须通过放置定义来定义伴随对象 object SomeClass 在同一个编译单元中 class SomeClass

另一个不同之处在于 编译器在类型的伴随对象(及其超类型)中搜索implicits。因此,如果您使用隐式转换,则在代码中定义 class SomeClass,您必须在伴侣对象中定义它们。

注释

两者的结合也解释了相同的编译单元限制。

  • scalac 无法编译 object SomeClass 直到它知道什么是私人成员 class SomeClass 它叫。
  • scalac 无法编译 class SomeClass 直到它知道它所调用的内容。因此,伴随对象必须不迟于编译 class SomeClass

它遵循它们必须同时编译。此外,当前编译器显然单独编译单独的文件(参见缺少对跨多个文件拆分类的支持),将其限制为相同的编译单元。


16
2017-07-22 22:01



“相同的编译单元”限制不仅仅是编译器的实现细节或部分编译器工程师的懒惰。它也是一种有用的方法来证明你有权访问类的私有成员,即打破封装:如果你可以编辑文件,那么封装已经不在窗口,所以你不会失去任何安全性通过将它们暴露给伴侣对象。如果任何人都可以随时随地定义伴随对象,只需向对象添加一个伴随对象,它们就可以简单地打破对第三方类的封装。 - Jörg W Mittag