Вы не можете создавать классы внутреннего члена (не static
) в вызове другому конструктору. От JLS §8.8.7.1:
Явный оператор вызова конструктора в конструктор тела (СИК: вызов this()
) не может ссылаться на любые переменные экземпляра или методы экземпляра или внутренних классов, объявленных в этом классе или любой суперкласс или использовать this
или super
в любом выражении; в противном случае возникает ошибка времени компиляции.
Причина в том, что внутренним классам, не относящимся к классу static
, может потребоваться доступ к классу во время его создания. Например:
public class OuterClass {
private String name;
private InnerClass inner;
public OuterClass(String name, InnerClass inner) {
this.name = name;
this.inner = inner;
}
public OuterClass(String name) {
this(name, new InnerClass()); // Will not compile
}
public class InnerClass {
public InnerClass() {
// Access to name is allowed since this inner class isn't static
System.out.println(name);
}
}
}
Основная проблема здесь состоит в том, что, когда мы строим не- static
внутреннего класса, он может получить доступ лиц, не являющиеся членов static
из его ограждающего экземпляра (OuterClass
, но ограждающие OuterClass
еще не сделали его вызов в super()
и поэтому считается небезопасным для доступа. Фактически, если этот код был разрешен для компиляции, он должен был распечатать null
из-за порядка вызова конструктора. Короче говоря, InnerClass
будет создан до вызова this.name = name
, аналогичная концепция к информации, представленной в this question.
Решение сделать InnerClass
static
внутренний класс и передать имя к нему непосредственно:
public class OuterClass {
private String name;
private InnerClass inner;
public OuterClass(String name, InnerClass inner) {
this.name = name;
this.inner = inner;
}
public OuterClass(String name) {
this(name, new InnerClass(name));
}
public static class InnerClass {
public InnerClass(String name) {
System.out.println(name);
}
}
}
InnerClass
не может получить доступ к name
из OuterClass
когда он объявил static
, поэтому мы должны передать его в явном виде на строительство сейчас, но это лучше, так как исходный код был бы сломан в любом случае.
Edit:
По Вашему вопросу:
Что меня смутило, что я могу создать объект в Date
типа в конструкторе Person
«s, до тех пор, как это не внутри метод this()
. Я могу это сделать: Date dt = new Date(birthMonth, birthDay, birthYear);
В чем разница между вышеуказанным и this(...., new Date(birthMonth, birthDay, birthYear), ...)
?
Разница заключается в том, что при вызове вне this()
, все звонки на super()
имели место, они занимают место как часть this()
из-за неявные вызовы на super()
, поэтому объект достиг точки, где это считается приемлемым для доступа. Ваш экземпляр Date
не может получить доступ к классу Person
, потому что нет никакого контекста для Person
и его полей, поэтому компилятор не разрешает его.
Вкратце, после того, как был вызван this()
, по крайней мере, звонки на super()
произошли, что является движущей силой этого ограничения, а также почему обескураживаются переопределяемые вызовы методов. Если метод переопределяется подклассом, а затем вызывается в конструкторе суперкласса, поля из подкласса могут быть доступны до того, как подкласс уже был инициализирован, даже если в возвращаются поля final
. В принципе, все это касается защиты себя от доступа к вашему классу до вызова super()
.
Дата статическая? – BevynQ
Нет. Я должен использовать частный внутренний класс (я думаю) – user2469763
@BevynQ Я попытался создать закрытый закрытый внутренний класс Date, и мой оригинальный код работает. Поэтому я попрошу инструктора, если это приемлемо. Между тем, любым другим способом? Спасибо – user2469763