Компилятор жалуется на & ldquo; пропущенное выражение возврата & rdquo; даже если невозможно достичь условия, при котором оператор return будет отсутствовать

Я не думаю, что реальная разница стала понятной в приведенных выше ответах.

Сначала, чтобы получить правильные слова:

  • Вложенный класс - это класс, который содержится в другом классе на уровне исходного кода.
  • It является статическим, если вы объявляете его со статическим модификатором.
  • Нестатический вложенный класс называется внутренним классом. (Я остаюсь с нестатическим вложенным классом.)

Ответ Мартина прав до сих пор. Тем не менее, актуальным вопросом является: Какова цель объявления статического кластера вложенным или нет?

Вы используете статические вложенные классы, если хотите просто сохранить свои классы вместе, если они принадлежат местно вместе или если вложенные класс используется исключительно в классе. Между статическим вложенным классом и каждым другим классом нет семантической разницы.

Нестатические вложенные классы - это другой зверь. Подобно анонимным внутренним классам, такие вложенные классы фактически закрывают. Это означает, что они захватывают свой окружающий масштаб и их охватывающий экземпляр и делают доступным. Возможно, пример пояснит это. См. Этот заглушка контейнера:

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)

Для полноты:

Анонимный класс - прекрасный пример нестатического вложенного класса, у которого просто нет имени, связанного с ним, и на него нельзя ссылаться позже.

29
задан Community 23 May 2017 в 10:34
поделиться

2 ответа

JLS 14.21, недостижимые операторы - это раздел, в котором рассматриваются следующие вопросы:

Оператор if, независимо от того, имеет ли он другую часть, обрабатывается необычным образом. , По этой причине это обсуждается отдельно в конце этого раздела.

В конечном итоге это связано с тем, как обрабатывается условная компиляция. Рассмотрим этот метод:

public int foo() {
    if (DEBUG) {
        return 5;
    }
}

Если DEBUG равен static final boolean true;, вы можете подумать, что компилятор должен быть достаточно умен, чтобы понять, что метод всегда будет возвращать 5. Но если его изменить на false, код больше не действителен.

Метод должен быть действительным для всех путей через метод без изменения исходного кода , что позволяет оптимизирующим компиляторам пропускать байт-код без модификаций исходного кода независимо от значения флага.

Сам конец связанной секции JLS подробно описан в деталях.

13
ответ дан Dave Newton 23 May 2017 в 10:34
поделиться

Причина, по которой компилятор жалуется, связана с этим ключевым моментом из раздела 14.21 спецификации языка Java , где обсуждаются недостижимые операторы:

За исключением специального режима из операторов while, do и for, выражение условия которых имеет постоянное значение true, значения выражений не учитываются при анализе потока.

Обратите внимание, что if не не одно из утверждений, которое имеет специальную обработку true постоянных условий. Причина, по которой он исключен из этой специальной обработки, заключается в том, что он позволяет использовать if в качестве формы условной компиляции, как объяснил Дейв Ньютон в своем ответе.

5
ответ дан Nandkumar Tekale 23 May 2017 в 10:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: