Почему this.super () невозможно в Java? - PullRequest
1 голос
/ 21 июня 2019

В следующем примере, если я создаю конструктор класса с именем example, примерно так:

public class Example{

    public Example(){
        this.super();
    }

}

Выше не будет работать, потому что javac Example.java сообщает о следующей ошибке компиляции:

Example.java:3: error: illegal qualifier; Object is not an inner class
        this.super();
            ^
1 error

Но не должно ли это работать, поскольку вместо того, чтобы неявно указывать this с помощью super(), мы явно указываем это с помощью this?

Ответы [ 3 ]

7 голосов
/ 21 июня 2019

Хотя вызов конструктора суперкласса путем вызова super(args) выглядит так, как будто это обычный вызов метода, этот синтаксис фактически отличается от обычного вызова метода и не подчиняется тем же правилам.Например:

  1. В конструкторе можно использовать только super(args).
  2. В качестве первой строки конструктора можно использовать только super(args).

В этом смысле, вероятно, полезно думать об этом не как о вызове метода, а просто как способ сообщить Java, что вы хотите сделать, чтобы инициализировать суперкласс.

Поскольку это неТипичный вызов метода, правила для обычных вызовов метода не применяются к нему.В результате вы не можете использовать префикс this., чтобы сделать объект получателя явным.Нет фундаментальной причины, по которой разработчики языка Java не могли бы сделать этот синтаксис легальным;они просто решили не делать этого.

3 голосов
/ 21 июня 2019

JLS , раздел 8.8.7.1 , управляет спецификациями для явных вызовов конструктора. В грамматике можно указать this.super().

Первичный . [TypeArguments] super ( [ArgumentList] );

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

Квалифицированные вызовы конструктора суперкласса начинаются с Первичного выражения или ExpressionName . Они позволяют конструктору подкласса явным образом указывать экземпляр объекта, который немедленно создается, в отношении прямого суперкласса (§8.1.3). Это может быть необходимо, когда суперкласс является внутренним классом.

Семантика указывает, что здесь this пытается указать включающий экземпляр, а не текущий экземпляр объекта. Ошибка компилятора, которую вы получаете, не самая очевидная, но здесь this пытается сослаться на включающий класс суперкласса, но Object не имеет включающего класса.

public class J {
    public J() {
        this.super();
    }
}

J.java:17: error: illegal qualifier; Object is not an inner class
        this.super();
            ^
1 error

Попробуем использовать this в качестве включающего экземпляра. Класс J имеет внутренний класс K, и Foo пытается создать подкласс J.K.

class J {
    public J() { }
    public class K {}
}
class Foo extends J.K {
    public Foo() {
        this.super();
    }
}

Теперь ошибка:

J.java:21: error: cannot reference this before supertype constructor has been called
            this.super();
            ^
1 error

Я могу заставить его работать только с основным выражением, отличным от this.

class Foo extends J.K {
    public Foo() {
        new J().super();
    }
}

Ошибка семантики, а не грамматическая ошибка, не позволяет использовать this.super().

0 голосов
/ 21 июня 2019

В Java классы инициализируются сверху вниз. Поэтому, если вы создаете класс, расширяющий объект, он вызывает конструктор объекта, а затем вызывает ваш класс.

Это также причина, по которой вы не можете инициализировать какие-либо поля перед вызовом super, ваш класс еще не создан. this ни на что не ссылается, так как шаблон объекта не был создан.

https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5

Дополнительная информация

...