Почему я должен использовать ключевое слово "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 и рассматривается как ошибка времени компиляции.но в случае
methodsForward 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.