Константное выражение времени компиляции поля Java
Приведенный ниже текст взят из jls http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html
Even then, there are a number of complications. If a final field is
initialized to a compile-time constant expression (§15.28) in the field
declaration, changes to the final field may not be observed, since uses of that
final field are replaced at compile time with the value of the constant
expression.
Может кто-нибудь, пожалуйста, дайте мне лучшее объяснение выше. я не мог понять утверждение changes to the final field may not be observed
, Пусть с помощью примера.
заранее спасибо
2 ответа
Я не мог понять заявление изменений в окончательном поле, возможно, не наблюдается
Это говорит о том, что если конечная переменная объявлена как постоянная времени компиляции, то любое изменение, внесенное в конечную переменную с использованием API отражения в дальнейшем, не будет видно программе во время выполнения.
Например, рассмотрим код, приведенный ниже:
import java.lang.reflect.*;
class ChangeFinal
{
private final int x = 20;//compile time constant
public static void change(ChangeFinal cf)
{
try
{
Class clazz = ChangeFinal.class;
Field field = clazz.getDeclaredField("x");
field.setAccessible(true);
field.set(cf , 190);//changed x to 190 for object cf
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
ChangeFinal cf = new ChangeFinal();
System.out.println(cf.x);//prints 20
change(cf);
System.out.println(cf.x);//prints 20
}
}
Вывод вышеуказанного кода:
20
20
ЗАЧЕМ?
Ответ заключается в выводе, предоставленном javap -c
команда для публичного статического void main:
public static void main(java.lang.String[]);
Code:
0: new #3; //class ChangeFinal
3: dup
4: invokespecial #11; //Method "<init>":()V
7: astore_1
8: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
15: pop
16: bipush 20
18: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
21: aload_1
22: invokestatic #15; //Method change:(LChangeFinal;)V
25: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_1
29: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
32: pop
33: bipush 20
35: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
38: return
}
В строке 16 (до changeFinal
метод называется) значение cf.x
жестко 20
, И в строке 33 (после changeFinal
метод называется) значение cf.x
снова жестко 20
, Поэтому, хотя изменение значения конечной переменной x
успешно сделано reflection API
во время исполнения, но из-за x
будучи постоянной времени компиляции, она показывает свое постоянное значение 20
,
Это означает, что если в классе у вас есть это:
public class Foo {
public final boolean fooBoolean = true; // true is a constant expression
public final int fooInt = 5; // 5 is a constant expression
}
Во время компиляции любая ссылка на Foo.fooBoolean
может быть заменен на true
и ссылки на Foo.fooInt
может быть заменен 5
, Если во время выполнения вы позже изменяете какое-либо из этих последних полей с помощью отражения, код, ссылающийся на него (как он был написан), может никогда не увидеть его.
Программа на Java вполне может наблюдать
final
поле, имеющее два разных значения в разное время, даже без отражения, без перекомпиляции нескольких версий класса и без чего-либо в этом направлении. Рассмотрим класс ниже:
class X {
static final int x = getX();
static int getX() {
System.out.println("X.x is now " + X.x);
return 1;
}
public static void main(String[] args) {
System.out.println("X.x is now " + X.x);
}
}
Вывод:
X.x is now 0
X.x is now 1
Это происходит потому, что часть кода (первая
println
) выполняется до того, как значение поля будет присвоено, так что код соблюдает начальное значение поля по умолчанию, равное 0. Поле имеет начальное значение по умолчанию до того, как оно будет назначено, даже если оно является окончательным, потому что это не постоянное поле. В приведенном вами тексте JLS говорится, что такого не может произойти, если поле объявлено как константа.