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

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

Ответ 1

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

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  

Ответ 2

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

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

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

  • Использование - это простое имя в инициализаторе переменной экземпляра 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

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

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

Ответ 4

Для любого класса в 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 и считается ошибкой времени компиляции.

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