java - Почему я должен использовать ключевое слово «this» для прямых ссылок?




class forward-reference (4)

Вы представили 3 случая:

  1. int a = b; int b;
    Это дает ошибку, потому что компилятор будет искать b в памяти, и его там не будет. но когда вы используете this ключевое слово, тогда оно явно указывает, что b определено в области видимости класса, все ссылки на классы будут найдены и, наконец, он его найдет.
  2. Второй сценарий довольно прост, и, как я описал, b определяется в области видимости до c и не будет проблемой при поиске b в памяти.
  3. int var1 = this.var2;
    int var2 = this.var1;
    В этом случае ошибки нет, потому что в каждом случае переменная определена в классе, и присваивание использует this что будет искать назначенную переменную в классе, а не только контекст, за которым она следует.

Когда я использую ключевое слово this для доступа к нестатической переменной в классе, Java не выдает никакой ошибки. Но когда я им не пользуюсь, Java выдает ошибку. Почему я должен использовать this ?

Я знаю, когда обычно я должен использовать this , но этот пример сильно отличается от обычного использования.

Пример:

class Foo {
//  int a = b; // gives error. why ?
    int a = this.b; // no error. why ?
    int b;
    int c = b;

    int var1 = this.var2; // very interesting
    int var2 = this.var1; // very interesting
}

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

public class ThisKeywordForwardReference {

    public ThisKeywordForwardReference() {
        super();
        System.out.println(b);
    }

    int a;
    int b;

    public ThisKeywordForwardReference(int a, int b) {
        super();
        this.a = a;
        this.b = b;
    }

}

Вы сказали, что int a = b; // gives error. why ? int a = b; // gives error. why ? дает ошибку времени компиляции, потому что b объявлен после a который является Illegal Forward Reference в Java и рассматривается как ошибка времени компиляции.

Но в случае methods Forward Reference становится легальным

int a = test();
int b;

int test() {
    return 0;
}

Но в моем коде конструктор с аргументом объявлен перед обоими a & b , но не выдает никакой ошибки во время компиляции, потому что System.out.println(b); будет заменен System.out.println(this.b); компилятором.

Ключевое слово this просто означает текущую ссылку на класс или ссылку, к которой обращаются метод, конструктор или атрибут.

A a1 = new A();  // Here this is nothing but a1
a1.test();  // Here this is again a1

Когда мы говорим a = this.b; это указывает, что b является текущим атрибутом класса, но когда мы говорим a = b; поскольку он не находится внутри нестатического блока, он не будет присутствовать и будет искать ранее объявленный атрибут, которого нет.



Полное описание приведено в разделе 8.3.3 Спецификации языка Java: « Прямые ссылки во время инициализации поля »

Прямая ссылка (ссылающаяся на переменную, которая еще не объявлена ​​в тот момент) является ошибкой только в том случае, если выполняются следующие условия:

  • Объявление переменной экземпляра в классе или интерфейсе C появляется текстуально после использования переменной экземпляра;

  • Использование - это простое имя в инициализаторе переменной экземпляра C или в инициализаторе экземпляра C;

  • Использование не на левой стороне назначения;

  • C является самым внутренним классом или интерфейсом, включающим использование.

См. Текст, выделенный жирным шрифтом: «использование - это простое имя». Простое имя - это имя переменной без дополнительной квалификации. В вашем коде b - простое имя, а this.b - нет.

Но почему?

Причина в том, что текст в примере в JLS гласит:

«Указанные выше ограничения предназначены для улавливания во время компиляции циклических или иным образом искаженных инициализаций».

Другими словами, они допускают this.b потому что считают, что квалифицированная ссылка повышает вероятность того, что вы тщательно продумали то, что делаете, но простое использование b вероятно, означает, что вы допустили ошибку.

Это обоснование дизайнеров языка Java. Насколько я знаю, так ли это на практике, никогда не исследовалось.

Порядок инициализации

Чтобы расширить вышесказанное, со ссылкой на комментарий Dukeling по этому вопросу, использование квалифицированной ссылки this.b , скорее всего, не даст вам this.b результатов.

Я ограничиваю это обсуждение переменными экземпляра, потому что OP только ссылается на них. Порядок, в котором присваиваются переменные экземпляра, описан в JLS 12.5 Создание экземпляров нового класса . Необходимо принять во внимание, что сначала создаются конструкторы суперкласса, а код инициализации (присваивания и блоки инициализации) выполняются в текстовом порядке.

Так дано

int a = this.b;
int b = 2;

в итоге вы получите ноль (значение b в момент a инициализатора a ), а b 2.

Даже более странные результаты могут быть достигнуты, если конструктор суперкласса вызывает метод, который переопределен в подклассе, и этот метод присваивает значение b .

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

Если вам нужно использовать this.b чтобы обойти ошибку компилятора, то вы, вероятно, пишете код, который будет очень сложно поддерживать после вас.





forward-reference