2013-07-06 5 views
3

Ниже текст из JLS http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3Java последнее поле во время компиляции константа

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. Может с помощью примера.

Заранее спасибо

ответ

7
не может наблюдаться

Я не мог понять изменения заявления в адрес конечного поле

Он говорит, что если конечные переменная объявлена ​​как время компиляции постоянного, то любое изменение в конечном переменном используя отражение 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 команды для общественности статической силы основных:

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.

+1

спасибо за описательный ответ – veritas

4

Это означает, что если в классе у вас есть это:

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 , Если во время выполнения вы позже меняете любое из этих окончательных полей через отражение, код, ссылающийся на него (как он был написан), может никогда не увидеть его.

+4

Другим примером является изменение fooInt до 6 в вышеприведенном классе, а затем перекомпиляция этого класса Foo без перекомпиляции классов, в которых используется класс foo. Тогда эти другие классы могут по-прежнему читать fooInt как 5 вместо 6. – MTilsted

+0

@MTilsted Хороший пример. Это действительно сбивает с толку. – Chao