У вас есть скрытая циклическая зависимость, которая запутывает JVM. Давайте посмотрим на ваш код.
class Recreate {
private static ArrayList FEATURES = new ArrayList();
public enum Car {
TESLA(FEATURES);
Car(ArrayList l) { }
}
public static class Garage {
final Car car;
Garage(Car car) {
this.car = car;
}
}
public static Garage ONE_CAR_GARAGE = new Garage(Car.TESLA);
}
Нам также понадобится несколько фрагментов с страницы из JLS .
Тип класса или интерфейса T будет инициализирован непосредственно перед первым вхождением любого из следующих:
blockquote>
- Используется статическое поле, объявленное T, и поле не является постоянной переменной (§ 4.12.4).
& nbsp;
12.4.2. Подробную процедуру инициализации
...
blockquote>
- Затем выполните либо инициализаторы переменных класса, и статические инициализаторы класса, либо инициализаторы полей интерфейса, в текстовом порядке, как если бы они были одним блоком.
Таким образом, наши статические данные инициализируются, когда они впервые упоминаются. Теперь ваш
Car.TESLA
неявноstatic final
, но он не является константой, согласно определению .Постоянная переменная является конечной переменной примитивного типа или введите String, которая инициализируется константным выражением
blockquote>. Итак, для наших целей здесь есть три статических непостоянных переменных:
FEATURES
,TESLA
иONE_CAR_GARAGE
.Теперь в вашем рабочем случае вы ссылаетесь на
Recreate.ONE_CAR_GARAGE
. Это ссылка на статическое поле вRecreate
, поэтомуFEATURES
, а затемONE_CAR_GARAGE
инициализируются. Затем во время инициализацияONE_CAR_GARAGE
,TESLA
инициализируется, так как ссылается на ее класс перечисления. Все хорошо.Однако, если мы слишком рано ссылаемся на перечисление, мы делаем вещи в неправильном порядке.
Recreate.Car.TESLA
получает ссылку, поэтомуTESLA
получает инициализацию.TESLA
ссылается наFEATURES
, поэтомуRecreate
должен быть инициализирован. Это заставляетFEATURES
иONE_CAR_GARAGE
инициализироваться до того, какTESLA
закончит существующие.Это скрытая зависимость, которая вас трогает.
Recreate.Car
зависит отRecreate
, который зависит отRecreate.Car
. Перемещение поляONE_CAR_GARAGE
в классGarage
приведет к тому, что он не будет инициализирован с помощьюFEATURES
и устранит вашу проблему.
Это поведение является ошибкой, попавшей в выпуск hakyll-images 0.3.1. Это было впоследствии исправлено в hakyll-изображениях 0.4 и выше. Просто обновитесь до последней версии, чтобы избавиться от этой проблемы.
Это был грубый недосмотр, и были добавлены тесты, чтобы это больше не повторилось.
Если вы хотите реализовать экземпляры самостоятельно, вы можете взглянуть на то, как это делается здесь .