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

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

object Foo { def bar = {} }

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

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

Примечание: здесь выводится код scalac -print

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

Ответ 1

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

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

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.

Ответ 2

При компиляции кода компилятор 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.