Почему я должен использовать ключевое слово "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
}
5 57

5 ответов:

переменные сначала объявляются, а затем назначаются. Этот класс такой же, как этот:

class Foo {
    int a;
    int b;
    int c = b;

    int var1;
    int var2;

    public Foo() {
        a = b;

        var1 = var2;
        var2 = var1;
    }
}

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

Вот описание:

    int a = b; // Error: b has not been defined yet
    int a = this.b; // No error: 'this' has been defined ('this' is always defined in a class)
    int b; 
    int c = b;  // No error: b has been defined on the line before  

полное описание раздел 8.3.3 спецификации языка Java:"Прямые Ссылки Во Время Инициализации Поля"

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

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

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

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

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

см. выделенный жирным шрифтом текст:"использование-это простое имя". Простое имя-это имя переменной без дальнейших уточнений. В коде b - это просто имя, но this.b нет.

но почему?

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

"ограничения выше предназначены для перехвата, во время компиляции, круговой или иначе уродливые инициализации. "

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

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

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

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

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

учитывая

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

вы закончитесь с a нулю (значение b во время aинициализатор был выполнен) и b быть 2.

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

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

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

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

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

для любого класса в 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 ? дает ошибку времени компиляции, потому что b объявлена после a что это Illegal Forward Reference в Java и рассматривается как ошибка времени компиляции.

но в случае methodsForward Reference будет legal

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; так как он не находится внутри нестатического блока this не будет присутствовать и будет искать атрибут, объявленный ранее, которого нет.

пожалуйста, посмотрите на спецификацию языка Java:https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3

это причина, ИМО: The usage is via a simple name.

в этом случае вы должны указать имя с помощью this.