Что такое Java-эквивалент объекта Scala?


В Scala мы можем написать

object Foo { def bar = {} }

Как это реализуется компилятором? Я могу вызвать Foo.bar(); С Java но new Foo(); из Java выдает ошибку cannot find symbol symbol: constructor Foo()

  • поддерживает ли СПМ синглетоны изначально?
  • можно ли иметь класс в Java, который не имеет конструктора?

Примечание: вот код, выводимый scalac -print

package <empty> {
  final class Foo extends java.lang.Object with ScalaObject {
    def bar(): Unit = ();
    def this(): object Foo = {
      Foo.super.this();
      ()
    }
  }
}
3 11

3 ответа:

Поддержка синглетов не находится на уровне языка, но язык предоставляет достаточно возможностей для их создания без каких-либо проблем.

Рассмотрим следующий код:

public class Singleton {
    private static final Singleton instance = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}
Это пример из Википедии, который объясняет, как можно сделать синглтон. Экземпляр хранится в закрытом поле, конструктор недоступен вне класса, метод возвращает этот единственный экземпляр.

Что касается конструкторов: каждый класс по умолчанию имеет так называемый конструктор по умолчанию , который не принимает аргументов и просто вызывает конструктор no-args суперкласса. Если суперкласс не имеет доступного конструктора без аргументов, вам придется написать явный конструктор.

Таким образом, класс должен иметь конструктор, но вы не должны писать его, если суперкласс имеет конструктор no-args.

При компиляции кода компилятор Scala создает эквивалент следующего кода Java:

public final class Foo {
    private Foo() {} // Actually, Foo doesn't have constructor at all
                     // It can be represented in bytecode, 
                     // but it cannot be represented in Java language

    public static final void bar() {
        Foo$.MODULE$.bar();
    }
}

public final class Foo$ implements ScalaObject {
    public static final Foo$ MODULE$;
    static {
        new Foo$();
    }
    private Foo$() { MODULE$ = this; }
    public final void bar() {
        // actual implementation of bar()
    }
}

Здесь Foo$ является фактической реализацией синглтона, тогда как Foo предоставляет метод static для взаимодействия с Java.

Джошуа блох в книге "эффективная Java" рекомендовал использовать перечисление для реализации синглетона.

См. этот вопрос: каков эффективный способ реализации синглетного шаблона в Java?