Подтвердить что ты не робот

Является ли "T.super" правовым выражением в JLS?

Рассмотрим следующий набор выражений:

class T {{
/*1*/   Object o = T.super; // error: '.' expected
/*2*/   o.toString();
}}

Попытка скомпилировать это приведет к сбою в строке /*1*/ с ошибкой:

error: '.' expected
    o = T.super;
               ^

как при использовании OpenJDK 1.8.0 (Ubuntu), так и в Oracle JDK 1.8 (Windows).

Однако Eclipse 4.5.0 (Mars) компилирует без ошибок, и это приводит к:

class T {
    T();
     0  aload_0 [this]
     1  invokespecial java.lang.Object() [8] // super()
     4  aload_0 [this]
     5  astore_1 [o]  // o = T.super
     7  invokevirtual java.lang.Object.toString() : java.lang.String [10]
    10  pop           // ^-- o.toString()
    11  return
}

Из этого вы можете видеть, что строка /*1*/ java-кода (строка 5 результата) правильно хранит this, отлитую как Object (понимание Eclipse T.super) в локальной переменной o. Когда код выполняется, он завершается нормально, а строка /*2*/ создает правильный результат.

До сих пор мне не удалось найти что-либо относящееся к o = T.super; в Java 8 Language Specification, то есть, является ли оно законным или нет. Поскольку в нем явно не указано, что это юридическое выражение, я предполагаю, что оно означает незаконно. Но почему, почему Eclipse считает это законным? Отсюда мой вопрос:

Является ли T.super юридическим выражением в соответствии с JLS?


Изменить: упростить код, удалив внутренний класс упаковки.
4b9b3361

Ответ 1

Нет, нет. См. Глава 19. Поиск ключевого слова super дает следующие конструкции:

  • подстановочные рамки: extends T/super T;
  • вызов явного конструктора: super(args);
  • доступ к полю: [Typename.]super.field;
  • вызов метода: [Typename.]super.method();
  • ссылка метода: super::method.

Тот факт, что он компилируется, может считаться ошибкой или расширением языка, хотя между ними нет реальной разницы.

Ответ 2

T.super не является юридическим выражением, потому что это не имеет смысла. Синтаксис super (с явным типом или без него) используется только для вызова методов из суперкласса. T.super не вызывает никакого метода (если это легальный синтаксис), он ссылается только на экземпляр класса. В вашем случае он ссылается на внешний экземпляр T. Правильный синтаксис будет T.this, который указывает на внешний this.

Определение вашего класса можно просмотреть следующим образом (с помощью имени внутреннего класса):

class Outer
{
    // Constructor Body
    {
        class Inner
        {{
            /*1*/   Outer o = Outer.super; // error: '.' expected
            /*2*/   o.toString();
        }};
        new Inner();
    }
}

Правильный способ ссылки на внешний класс будет

Outer o = Outer.this; // valid

Ответ 3

Принятие этого синтаксиса было давней ошибкой в Eclipse, которая была исправлена ​​для этапа 5 в Eclipse 4.6.

Ответ 4

Это верно в соответствии с JLS. Спецификация JLS "Форма super.Identifier относится к полю с именем Identifier текущего объекта, но с текущим объектом, рассматриваемым как экземпляр суперкласса текущего класса".

На основе этого супер является экземпляром суперкласса.

Также JLS заявляет, что "Это ошибка времени компиляции, если текущий класс не является внутренним классом самого класса T или T".

В вашем случае это, очевидно, внутренний класс. Вы можете узнать версию Java, используемую в eclipse.