Ответ 1
Я попробую объяснить его на уровне компилятора.
Скажем, у вас есть такой метод, как:
int x;
x = 1;
System.out.println(x);
Будет выполнена компиляция и выполнение. Если вы измените метод на это:
System.out.println(x);
int x;
x = 1;
Он даже не будет компилировать то же самое с вашим примером.
Компилятор копирует код { }
intializer в
ctor
, а также инициализацию x=1
.
Как вы сказали, это работает, если вы установите x=1
перед { }
intializer.
public class MainC {
public static void main(String args[]) {
new MainC();
}
int x=1;
{
System.out.println(x);
}
}
См. следующий байт-код Java:
public MainC();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field x:I
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_0
13: getfield #2 // Field x:I
16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
19: return
LineNumberTable:
line 1: 0
line 7: 4
line 9: 9
line 10: 19
Поле x
объявлено и получает значение 1
, прежде чем оно будет использоваться в
System.out.println
вызов.
Итак, почему это не работает, если вы установите его после { }
по той же причине
вы не можете использовать Кодекс моего второго примера. Поле объявляется после использования, что не имеет смысла.
Итак, почему он работает с ключевым словом this
?!
Давайте посмотрим на какой-то код:
public class Main {
public static void main(String args[]) {
new Main();
}
{ System.out.println(this.x); } //Error here
int x=1;
}
Соответствующий Java-байт-код для ctor:
public Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_0
8: getfield #3 // Field x:I
11: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
14: aload_0
15: iconst_1
16: putfield #3 // Field x:I
19: return
LineNumberTable:
line 1: 0
line 7: 4
line 9: 14
Так что происходит здесь? Легко говоря, ключевое слово this
загружает Основной объект
ссылку на стек. После этого к полю x можно получить доступ, поэтому вызов System.out.println
может быть успешно выполнен.