Когда вычисляются функции внутри переменной Enum? - PullRequest
2 голосов
/ 21 октября 2019

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

public enum MyOwnEnum    {

    JANVIER("janvier", "3101"),
    FEVRIER("février", new DateCalculator().getLeapYear()),
    MARS("mars", "3103"),
    AVRIL("avril", "3004");

    // Two variables, the protected constructor, getters

}

Как поведет себя код? Будет ли метод вычисляться непосредственно во время компиляции и фиксироваться, или он будет вычисляться каждый раз, когда кто-то вызывает от FEVRIER до MyOwnEnum.FEVRIER или MyOwnEnum.valueOf("FEVRIER")? Или исправлено, но во время выполнения?

Ответы [ 2 ]

4 голосов
/ 21 октября 2019

Константы перечисления создаются один раз во время выполнения или, более конкретно, во время загрузки класса.

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

public enum TestEnum {
    ONE("One at " + System.nanoTime()),
    TWO("Two at " + System.nanoTime());

    String value;

    TestEnum(String value) {
        System.out.println(value);
        this.value = value;
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println("Loading");

        Class.forName("TestEnum"); // Load class

        System.out.println("Evaluating");

        System.out.println(TestEnum.ONE.value); // Evaluate value one
        System.out.println(TestEnum.TWO.value); // Evaluate value two
    }
}

Это генерирует следующий вывод:

Loading
One at 31207575500045
Two at 31207575625697
Evaluating
One at 31207575500045
Two at 31207575625697

Обратите внимание, что значения не изменяются при последующих вызовах.

2 голосов
/ 21 октября 2019

Если вы посмотрите на байт-код, сгенерированный вашим ENUM, вы увидите, что приведенный выше код аналогичен приведенному ниже коду:

class MyOwnEnum{
    public static MyOwnEnum JANVIER = new MyOwnEnum("janvier", "3101");
    public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));
    public static MyOwnEnum MARS = new MyOwnEnum("mars", "3103");
}

Это означает, что ваш код создаст объект DateCalculator() и вызовите getLeapYear(), когда он запустит статическую переменную FEVRIER и сохранит все свойства статической переменной:

  1. Статическая переменная, которая принадлежит классу, а неto object (instance)
  2. Статические переменные инициализируются только один раз, в начале выполнения.
  3. Статические переменные будут инициализироваться в первую очередь, до инициализации любых переменных экземпляра
  4. Одна копия, которая будет использоваться всеми экземплярами класса
  5. Доступ к статической переменнойнепосредственно по имени класса и не нуждается в каком-либо объекте.

Поскольку FEVRIER является статической переменной public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));, эти строки кода будут выполняться только один раз для загрузчика класса, загружающего класс,

Вот байт-код для справки:

21: ldc           #26                 // String FEVRIER
      23: iconst_1
      24: ldc           #27                 // String fΘvrier
      26: new           #29                 // class com/java8/demo/DateCalculator
      29: dup
      30: invokespecial #31                 // Method com/java8/demo/DateCalculator."<init>":()V
      33: invokevirtual #33                 // Method com/java8/demo/DateCalculator.getLeapYear:()Ljava/lang/String;
      36: invokespecial #20                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
      39: putstatic     #37                 // Field FEVRIER:Lcom/java8/demo/MyOwnEnum;
      42: new           #1                  // class com/java8/demo/MyOwnEnum
      45: dup
      46: ldc           #39                 // String MARS
      48: iconst_2
      49: ldc           #40                 // String mars
      51: ldc           #42                 // String 3103
      53: invokespecial #20                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
      56: putstatic     #44                 // Field MARS:Lcom/java8/demo/MyOwnEnum;
      59: new           #1                  // class com/java8/demo/MyOwnEnum
...