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.
这意味着,必须有与它的同伴对象的类,只是一个类和对象以相同的(完全限定)名称之间的区别。 这是什么区别?
让我们调用类class SomeClass
(尽管它也可以如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
,直到它知道什么implicits它调用。 所以同伴对象必须不迟于编译class SomeClass
。
它遵循他们必须在同一时间进行编译。 此外,电流的编译器显然单独编译独立的文件(参见缺乏对在多个文件分割类的支持),将其限制到相同的编译单元。
文章来源: What's the difference between a class with a companion object and a class and object with the same name?