Подтвердить что ты не робот

Синглтоны как синтетические классы в Scala?

Я читаю Программирование в Scala, и я не понимаю следующее предложение (pdf стр .112):

Каждый объект singleton реализуется как экземпляр синтетического класса, на который ссылается статическая переменная, поэтому они имеют ту же семантику инициализации, что и статическая статистика Java.

Означает ли это, что если у меня есть singleton FooBar в Scala, компилятор создаст класс с именем FooBar $?

Также, что означает автор, ссылаясь на статическую переменную? Есть ли скрытая статическая переменная где-то содержащая ссылку на некоторый класс FooBar $?

Я ценю любую помощь здесь.

4b9b3361

Ответ 1

Более точно описана глава 31 того же "Программирование в Scala":

Java не имеет точного эквивалента одиночному объекту, но имеет статические методы.

Трансляция объектов singleton с помощью Scala использует комбинацию статических и экземплярных методов. Для каждого объекта Scala singleton, компилятор создаст класс Java для объекта со знаком доллара, добавленным в конец.
Для одноэлементного объекта с именем App компилятор создает класс Java с именем App$.
Этот класс имеет все методы и поля объекта Scala singleton.
Класс Java также имеет одно статическое поле с именем MODULE$, чтобы удерживать один экземпляр класса, созданного во время выполнения.
В качестве полного примера предположим, что вы скомпилируете следующий одноэлементный объект:

object App {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

Scala создаст класс Java App $со следующими полями и методами:

$ javap App$
public final class App$ extends java.lang.Object
    implements scala.ScalaObject{
  public static final App$ MODULE$;
  public static {};
  public App$();
  public void main(java.lang.String[]);
  public int $tag();
}

Это перевод для общего случая.

Ответ 2

Вы в основном правы.

Если у вас синглтон

object Singleton {
  def method = "Method result"
}

то компиляция дает вам

Singleton.class
Singleton$.class

и для байт-кода, который вы найдете, сначала для Singleton:

public final class Singleton extends java.lang.Object{
public static final java.lang.String method();
  Signature: ()Ljava/lang/String;
  Code:
   0:   getstatic   #11; //Field Singleton$.MODULE$:LSingleton$;
   3:   invokevirtual   #13; //Method Singleton$.method:()Ljava/lang/String;
   6:   areturn
}

то есть публичный статический метод для каждого метода класса, который ссылается на то, что называется Singleton$.MODULE$, и в Singleton$:

public final class Singleton$ extends java.lang.Object implements scala.ScalaObject{
public static final Singleton$ MODULE$;
  Signature: LSingleton$;

public static {};
  Signature: ()V
  Code:
   0:   new #9; //class Singleton$
   3:   invokespecial   #12; //Method "<init>":()V
   6:   return


public java.lang.String method();
  Signature: ()Ljava/lang/String;
  Code:
   0:   ldc #16; //String Method result
   2:   areturn


private Singleton$();
  Signature: ()V
  Code:
   0:   aload_0
   1:   invokespecial   #20; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   putstatic   #22; //Field MODULE$:LSingleton$;
   8:   return
}

Где вы видите, что MODULE$ - это то, что содержит экземпляр Singleton$, а method - обычный метод.

Итак, все, что ему действительно нужно: создайте Singleton$ со статическим полем MODULE$, чтобы сохранить уникальный экземпляр самого себя, заполнить это поле, а затем создать Singleton со статическими методами, которые пересылают все статические вызовы для соответствующих методов из Singleton$.