что означает ключевое слово "this" в блоке инициализатора? [дубликат]

этот вопрос уже есть ответ здесь:

вот мой код:

class StaticBlock {
    {       
        println("initializer block : " + message);
    }
    public StaticBlock(String message) {
        this.message = message;
    }
    private String message;
}

теперь проблема в том, что в блоке инициализатора

{       
    println("initializer block : " + message);
}

если я добавить this ключевое слово перед message, он работает, но есть ошибка при отсутствии this ключевое слово.

и компилятор говорит:

StaticBlockDemo.java:34: illegal forward reference
                println("initializer block : " + message);
                                                 ^
1 error

почему они не одинаковые?

4 ответов


Я не знаю причины, но это может помочь, чтобы прочитать соответствующие разделы спецификации языка Java.

8.6. Инициализаторы Экземпляра

инициализаторы экземпляра могут ссылаться на текущий объект с помощью ключевого слова this (§15.8.3), чтобы использовать ключевое слово super (§15.11.2, §15.12), и использовать любые переменные типа в области.

использование переменных экземпляра, объявления появляются дословно После использования иногда ограничено, Даже если эти переменные находятся в области. Точные правила, регулирующие прямую ссылку на переменные экземпляра, см. в §8.3.2.3.

8.3.2.3. Ограничения на использование полей при инициализации

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

  • использование происходит в экземпляре (соответственно static) инициализатора переменной C или в экземпляре (соответственно статическом) инициализатора C.

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

  • использование через простое имя.

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

вот пример из этого раздела спецификации, обрезанный, чтобы проиллюстрировать конкретный момент, о котором вы спрашиваете:

class UseBeforeDeclaration {

    {
        j = 200;
          // ok - assignment
        j = j + 1;
          // error - right hand side reads before declaration
        int k = j = j + 1;
          // error - illegal forward reference to j
        int n = j = 300;
          // ok - j at left hand side of assignment
        int h = j++;
          // error - read before declaration
        int l = this.j * 3;
          // ok - not accessed via simple name
    }

    int j;
}

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

new StaticBlock("abc");

он будет печатать

initializer block : null

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

12.5. Создание новых экземпляров класса

[...] указанный конструктор обрабатывается для инициализации нового объекта с помощью следующей процедуры:

[...]

4. Выполните инициализаторы экземпляра и инициализаторы переменных экземпляра для этого класса [...]

5. Выполните остальную часть тела этого конструктора. [...]


если я добавляю " это "ключевое слово перед "сообщением", оно работает, но ошибка при отсутствии "этого" ключевого слова. почему они не одинаковые?

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

public StaticBlock(String message) {
    this.message = message;
}

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

при использовании this затем он присвоит значение переменной текущая переменная объекта.


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

чтобы ссылаться на информацию, специфичную для одного класса объектов, мы можем использовать this внутри кода объекта (класса). Он сообщает программе, что вы хотите использовать current переменные и значения объектов. Используя this.message = message, вы назначаете значение сообщения, которое было передано в функция и сохранение ее в переменной сообщения объекта.

в этом есть аспекты области, где message имеет локальную область, и this.message объем за весь объект. Вот почему, когда вы пытались вызвать сообщение в коде печати:println("initializer block : " + message);, сообщение локальной переменной не существовало в рамках этой функции.


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