Почему я должен использовать ключевое слово "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 ответов:
переменные сначала объявляются, а затем назначаются. Этот класс такой же, как этот:
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 случаях:
int a = b; int b;
Это дает ошибку, потому что компилятор будет искатьb
в памяти его и не будет. но когда вы используетеthis
ключевое слово, то это явно указывает, чтоb
определяется в области класса, все ссылки на класс будут искать его, и, наконец, он найдет его.
- второй сценарий довольно прост и, как я описал,
b
определена в области раньшеc
и не будет проблемой при поискеb
в памяти.
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 и рассматривается как ошибка времени компиляции.но в случае
methods
Forward Reference
будет legalint 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
.