今天在听.NET课的时候老师提到了.NET的常数所隐含的版本问题,想到java,于是回来try了一下,发现java也有类似的版本问题。在开发较大型项目的时候是个不能忽略的问题,所以写下了供以后参考。
可以看下面的两个类:
Component.java
public class Component
{
public static final int MaxEntriesInList = 50;
}
App.java
public class App{
public static void main(String args[]){
System.out.println("The MaxEntriesInList: " + Component.MaxEntriesInList);
}
}
------------------------------------------------------------------------------------------------
其运行结果为:The MaxEntriesInList: 50
------------------------------------------------------------------------------------------------
然后我们将Component.java做如下修改:
public class Component
{
public static final int MaxEntriesInList = 100;
}
并重新编译Component.java,然后再运行App
-----------------------------------------------------------------------------------------------
其运行结果为:The MaxEntriesInList: 50
------------------------------------------------------------------------------------------------
我们可以看到运行结果丝毫没有改变,那么我们如果重新编译App.java,然后再运行
------------------------------------------------------------------------------------------------
其运行结果为:The MaxEntriesInList: 100
------------------------------------------------------------------------------------------------
其实这个时候如果我们删除了Component.class文件App.class也是能够正确运行的。
在.NET中给出的解释是因为:当编译器发现MaxEntriesInList是一个值为50的常数,所以它直接把整数值50嵌入到应用程序的中间代码,所以在运行Component.class文件甚至都不会被加载
那下面我们来看看通过javap反汇编class文件生成的文件(应该也叫中间码吧):
Component反汇编的文件如下(Component.txt)(还是将里面的字段MaxEntriesInList值改我50,并编译):
Compiled from "App.java"
public class App extends java.lang.Object{
public App();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String The max entries in list: 50
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
App反汇编的文件的内容如下(App.txt):
Compiled from "App.java"
public class App extends java.lang.Object{
public App();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String The max entries in list: 50
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
反汇编后的程序虽然有些不好明白(主要是我也不懂),但应该能从里面看到些信息:上面加颜色的那句,我的理解应该就是将MaxEntriesInList的值50嵌入到App.class的程序中了,所以我认为,.net的原因应该就是这个的原因,常量被嵌入到了被引用的程序中去了(个人理解,不正确希望能指出)。
解决方法:C#中用的是一个static readonly修饰符来代替const来避免该问题,这样的话每次都会是从动态内存中去读加载的字段。在java中我不知道如何解决这个问题,抑或是这个问题不需要解决,希望留言^_^