Const.java:
1:  public class Const {  
2:      public static final int VALUE = 600;  
3:      public void test() {  
4:          int a = VALUE;  
5:          System.out.println("a=" + a);  
6:      }  
7:      public static void main(String[] args) {  
8:          new Const().test();  
9:      }  
10:  }  
ConstClient.java:
1:  public class ConstClient {  
2:      public void test() {  
3:          int b = Const.VALUE;  
4:          System.out.println("b=" + b);  
5:      }  
6:      public static void main(String[] args) {  
7:          new ConstClient().test();  
8:      }  
9:  }  
Compile and run both classes:
Const.java displays:
 a=600  
ConstClient.java displays:
 b=600  
So far so good, this is what we expected.
Let's try disassembling them with "javap -c Const"
1:  Compiled from "Const.java"  
2:  public class Const extends java.lang.Object{  
3:  public static final int VALUE;  
4:  public Const();  
5:   Code:  
6:    0:     aload_0  
7:    1:     invokespecial     #1; //Method java/lang/Object."<init>":()V  
8:    4:     return  
9:  public void test();  
10:   Code:  
11:    0:     sipush     600  
12:    3:     istore_1  
13:    4:     getstatic     #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
14:    7:     new     #3; //class java/lang/StringBuilder  
15:    10:     dup  
16:    11:     invokespecial     #4; //Method java/lang/StringBuilder."<init>":()V  
17:    14:     ldc     #5; //String a=  
18:    16:     invokevirtual     #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
19:    19:     iload_1  
20:    20:     invokevirtual     #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
21:    23:     invokevirtual     #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
22:    26:     invokevirtual     #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
23:    29:     return  
24:  public static void main(java.lang.String[]);  
25:   Code:  
26:    0:     new     #10; //class Const  
27:    3:     dup  
28:    4:     invokespecial     #11; //Method "<init>":()V  
29:    7:     invokevirtual     #12; //Method test:()V  
30:    10:     return  
31:  }  
and "javap -c ConstClient"
1:  Compiled from "ConstClient.java"  
2:  public class ConstClient extends java.lang.Object{  
3:  public ConstClient();  
4:   Code:  
5:    0:     aload_0  
6:    1:     invokespecial     #1; //Method java/lang/Object."<init>":()V  
7:    4:     return  
8:  public void test();  
9:   Code:  
10:    0:     sipush     600  
11:    3:     istore_1  
12:    4:     getstatic     #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
13:    7:     new     #3; //class java/lang/StringBuilder  
14:    10:     dup  
15:    11:     invokespecial     #4; //Method java/lang/StringBuilder."<init>":()V  
16:    14:     ldc     #5; //String b=  
17:    16:     invokevirtual     #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
18:    19:     iload_1  
19:    20:     invokevirtual     #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
20:    23:     invokevirtual     #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
21:    26:     invokevirtual     #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
22:    29:     return  
23:  public static void main(java.lang.String[]);  
24:   Code:  
25:    0:     new     #10; //class ConstClient  
26:    3:     dup  
27:    4:     invokespecial     #11; //Method "<init>":()V  
28:    7:     invokevirtual     #12; //Method test:()V  
29:    10:     return  
30:  }  
We see that from Const.class line 11 and ConstClient.class line 10, the constant value 600 is pushed onto the stack memory at slot #1.
Let's try changing Const.java constant value from 600 to 500.
1:  public class Const {  
2:      public static final int VALUE = 500;  
3:      public void test() {  
4:          int a = VALUE;  
5:          System.out.println("a=" + a);  
6:      }  
7:      public static void main(String[] args) {  
8:          new Const().test();  
9:      }  
10:  }  
Compile Const.java and run produces:
 a=500  
Rerun ConstClient without recompilation produces strange result:
 b=600  
Let's take a peek by disassembling Const.class:
1:  Compiled from "Const.java"  
2:  public class Const extends java.lang.Object{  
3:  public static final int VALUE;  
4:  public Const();  
5:   Code:  
6:    0:     aload_0  
7:    1:     invokespecial     #1; //Method java/lang/Object."<init>":()V  
8:    4:     return  
9:  public void test();  
10:   Code:  
11:    0:     sipush     500  
12:    3:     istore_1  
13:    4:     getstatic     #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
14:    7:     new     #3; //class java/lang/StringBuilder  
15:    10:     dup  
16:    11:     invokespecial     #4; //Method java/lang/StringBuilder."<init>":()V  
17:    14:     ldc     #5; //String a=  
18:    16:     invokevirtual     #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
19:    19:     iload_1  
20:    20:     invokevirtual     #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
21:    23:     invokevirtual     #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
22:    26:     invokevirtual     #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
23:    29:     return  
24:  public static void main(java.lang.String[]);  
25:   Code:  
26:    0:     new     #10; //class Const  
27:    3:     dup  
28:    4:     invokespecial     #11; //Method "<init>":()V  
29:    7:     invokevirtual     #12; //Method test:()V  
30:    10:     return  
31:  }  
We see that line 11 pushes our new constant value 500 onto the stack.
Let's take another peek at ConstClient.class:
1:  Compiled from "ConstClient.java"  
2:  public class ConstClient extends java.lang.Object{  
3:  public ConstClient();  
4:   Code:  
5:    0:     aload_0  
6:    1:     invokespecial     #1; //Method java/lang/Object."<init>":()V  
7:    4:     return  
8:  public void test();  
9:   Code:  
10:    0:     sipush     600  
11:    3:     istore_1  
12:    4:     getstatic     #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
13:    7:     new     #3; //class java/lang/StringBuilder  
14:    10:     dup  
15:    11:     invokespecial     #4; //Method java/lang/StringBuilder."<init>":()V  
16:    14:     ldc     #5; //String b=  
17:    16:     invokevirtual     #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
18:    19:     iload_1  
19:    20:     invokevirtual     #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
20:    23:     invokevirtual     #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
21:    26:     invokevirtual     #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
22:    29:     return  
23:  public static void main(java.lang.String[]);  
24:   Code:  
25:    0:     new     #10; //class ConstClient  
26:    3:     dup  
27:    4:     invokespecial     #11; //Method "<init>":()V  
28:    7:     invokevirtual     #12; //Method test:()V  
29:    10:     return  
30:  }  
Line 10 tells us that for some reason our program pushes 600 onto the stack not 500 - our constant value is still 600! It seems like javac burned the constant value into ConstClient.class instead of JVM resolving it through Const.class!
- "Extra care should be taken when hot-deploying classes with public constants as they could potentially break your code during runtime."
 
No comments:
Post a Comment