В чем разница между классом с сопутствующим объектом и классом и объектом с одинаковым именем?
"Сопутствующий объект" класса 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.
Это подразумевает, что должно быть различие между классом с его сопутствующим объектом и просто классом и объектом с тем же (полностью определенным) именем. Что это за различие?
1 ответ
Давайте назовем класс class SomeClass
(хотя это также может быть, например, trait
).
Частные участники
Методы сопутствующего объекта (object SomeClass
) иметь доступ к закрытым методам / данным экземпляров class SomeClass
,
Если ваш сопутствующий объект использует только открытый интерфейс вашего класса (например, просто определяет константы), практической разницы нет. Но в ряде случаев полезно разрешить служебным функциям получать доступ к закрытым членам. Например, object SomeClass
может определить фабричный метод apply
который устанавливает частных членов class SomeClass
, без необходимости выставлять сеттеры в общедоступном интерфейсе. Поэтому в таких случаях вы должны определить сопутствующий объект, поместив определение object SomeClass
в том же модуле компиляции, что и class SomeClass
,
Другое отличие состоит в том, что компилятор ищет импликации в сопутствующих объектах типа (и его супертипах). Так что, если вы используете неявные преобразования, вы определяете в коде class SomeClass
Вы должны определить их в сопутствующем объекте.
Комментарии
Комбинация этих двух также объясняет ограничение для одной и той же единицы компиляции.
scalac
не может скомпилироватьobject SomeClass
пока он не знает, что частные членыclass SomeClass
это звонки.scalac
не может скомпилироватьclass SomeClass
пока он не знает, что подразумевает, он называет. Таким образом, объект-компаньон должен быть скомпилирован не позднее, чемclass SomeClass
,
Следовательно, они должны быть скомпилированы одновременно. Кроме того, текущий компилятор, по-видимому, компилирует отдельные файлы отдельно (см. Отсутствие поддержки разделения классов по нескольким файлам), ограничивая его одним и тем же модулем компиляции.