Я не думаю, что реальная разница стала понятной в приведенных выше ответах.
Сначала, чтобы получить правильные слова:
Ответ Мартина прав до сих пор. Тем не менее, актуальным вопросом является: Какова цель объявления статического кластера вложенным или нет?
Вы используете статические вложенные классы, если хотите просто сохранить свои классы вместе, если они принадлежат местно вместе или если вложенные класс используется исключительно в классе. Между статическим вложенным классом и каждым другим классом нет семантической разницы.
Нестатические вложенные классы - это другой зверь. Подобно анонимным внутренним классам, такие вложенные классы фактически закрывают. Это означает, что они захватывают свой окружающий масштаб и их охватывающий экземпляр и делают доступным. Возможно, пример пояснит это. См. Этот заглушка контейнера:
public class Container {
public class Item{
Object data;
public Container getContainer(){
return Container.this;
}
public Item(Object data) {
super();
this.data = data;
}
}
public static Item create(Object data){
// does not compile since no instance of Container is available
return new Item(data);
}
public Item createSubItem(Object data){
// compiles, since 'this' Container is available
return new Item(data);
}
}
В этом случае вы хотите получить ссылку от дочернего элемента в родительский контейнер. Используя нестатический вложенный класс, это работает без какой-либо работы. Вы можете получить доступ к закрывающему экземпляру Container с синтаксисом Container.this
.
Более подробные пояснения к хардкору:
Если вы посмотрите на байт-коды Java, которые генерирует компилятор для (нестатического ) вложенный класс может стать еще яснее:
// class version 49.0 (49)
// access flags 33
public class Container$Item {
// compiled from: Container.java
// access flags 1
public INNERCLASS Container$Item Container Item
// access flags 0
Object data
// access flags 4112
final Container this$0
// access flags 1
public getContainer() : Container
L0
LINENUMBER 7 L0
ALOAD 0: this
GETFIELD Container$Item.this$0 : Container
ARETURN
L1
LOCALVARIABLE this Container$Item L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 1
public <init>(Container,Object) : void
L0
LINENUMBER 12 L0
ALOAD 0: this
ALOAD 1
PUTFIELD Container$Item.this$0 : Container
L1
LINENUMBER 10 L1
ALOAD 0: this
INVOKESPECIAL Object.<init>() : void
L2
LINENUMBER 11 L2
ALOAD 0: this
ALOAD 2: data
PUTFIELD Container$Item.data : Object
RETURN
L3
LOCALVARIABLE this Container$Item L0 L3 0
LOCALVARIABLE data Object L0 L3 2
MAXSTACK = 2
MAXLOCALS = 3
}
Как вы видите, компилятор создает скрытое поле Container this$0
. Это устанавливается в конструкторе, который имеет дополнительный параметр типа Container для указания экземпляра-оболочки. Вы не можете увидеть этот параметр в источнике, но компилятор неявно генерирует его для вложенного класса.
Пример Мартина
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
был бы скомпилирован для вызова чего-то вроде (в байтекодах)
new InnerClass(outerObject)
Для полноты:
Анонимный класс - прекрасный пример нестатического вложенного класса, у которого просто нет имени, связанного с ним, и на него нельзя ссылаться позже.
JLS 14.21, недостижимые операторы - это раздел, в котором рассматриваются следующие вопросы:
Оператор if, независимо от того, имеет ли он другую часть, обрабатывается необычным образом. , По этой причине это обсуждается отдельно в конце этого раздела.
В конечном итоге это связано с тем, как обрабатывается условная компиляция. Рассмотрим этот метод:
public int foo() {
if (DEBUG) {
return 5;
}
}
Если DEBUG
равен static final boolean true;
, вы можете подумать, что компилятор должен быть достаточно умен, чтобы понять, что метод всегда будет возвращать 5
. Но если его изменить на false
, код больше не действителен.
Метод должен быть действительным для всех путей через метод без изменения исходного кода , что позволяет оптимизирующим компиляторам пропускать байт-код без модификаций исходного кода независимо от значения флага.
Сам конец связанной секции JLS подробно описан в деталях.
Причина, по которой компилятор жалуется, связана с этим ключевым моментом из раздела 14.21 спецификации языка Java , где обсуждаются недостижимые операторы:
За исключением специального режима из операторов
while
,do
иfor
, выражение условия которых имеет постоянное значениеtrue
, значения выражений не учитываются при анализе потока.
Обратите внимание, что if
не не одно из утверждений, которое имеет специальную обработку true
постоянных условий. Причина, по которой он исключен из этой специальной обработки, заключается в том, что он позволяет использовать if
в качестве формы условной компиляции, как объяснил Дейв Ньютон в своем ответе.