这是在以下情况下可能发生的问题的示例单独编译.
单独编译的主要微妙之处在于,当编译调用者类时,某些信息将从被调用者复制到调用者的类文件中。如果调用者稍后针对不同版本的被调用者运行,则从旧版本的被调用者复制的信息可能与新版本的被调用者不完全匹配,并且结果可能会有所不同。仅通过查看源代码很难看出这一点。这个例子展示了当进行这样的修改时,程序的行为如何以令人惊讶的方式发生变化。
在示例中,Name
and SimpleName
被修改并重新编译,但旧的编译二进制文件ExtendedName
至今仍在使用。这就是“源代码”的真正含义ExtendedName
不可用。”当针对修改后的类层次结构编译程序时,它记录的信息与针对旧层次结构编译时记录的信息不同。
让我详细介绍一下我为重现此示例而执行的步骤。
在一个空目录中,我创建了两个子目录v1
and v2
. In v1
我将第一个示例代码块中的类放入单独的文件中Name.java
, SimpleName.java
, and ExtendedName.java
.
请注意,我没有使用v1
and v2
目录作为包。所有这些文件都位于未命名的包中。另外,我使用单独的文件,因为如果它们都是嵌套类,则很难单独重新编译其中的一些文件,这对于示例的工作是必要的。
另外我将主程序重命名为Test1.java
并修改如下:
class Test1 {
public static void main(String[] args) {
Name m = new ExtendedName("a","b");
Name n = new ExtendedName("a","c");
System.out.println(m.compareTo(n));
}
}
In v1
我编译了所有内容并运行 Test1:
$ ls
ExtendedName.java Name.java SimpleName.java Test1.java
$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ javac *.java
$ java Test1
-1
Now, in v2
我把Name.java
and SimpleName.java
文件,使用泛型进行修改,如第二个示例代码块所示。我也复制进去v1/Test1.java
to v2/Test2.java
并相应地重命名该类,但除此之外代码是相同的。
$ ls
Name.java SimpleName.java Test2.java
$ javac -cp ../v1 *.java
$ java -cp .:../v1 Test2
0
这表明结果m.compareTo(n)
之后就不同了Name
and SimpleName
进行了修改,同时使用旧的ExtendedName
二进制。发生了什么?
我们可以通过查看反汇编的输出来看到差异Test1
类(针对旧类编译)和Test2
类(针对新类编译)以查看为该类生成了哪些字节码m.compareTo(n)
称呼。还在v2
:
$ javap -c -cp ../v1 Test1
...
29: invokeinterface #8, 2 // InterfaceMethod Name.compareTo:(Ljava/lang/Object;)I
...
$ javap -c Test2
...
29: invokeinterface #8, 2 // InterfaceMethod Name.compareTo:(LName;)I
...
编译时Test1
,将信息复制到Test1.class
文件是对compareTo(Object)
因为这就是方法Name
界面已至此。使用修改后的类,编译Test2
结果是调用的字节码compareTo(Name)
因为这就是修改后的内容Name
界面现在有了。什么时候Test2
运行时,它会寻找compareTo(Name)
方法并因此bypasses the compareTo(Object)
方法中的ExtendedName
上课、打电话SimpleName.compareTo(Name)
反而。这就是行为不同的原因。
注意老人的行为Test1
binary不改变:
$ java -cp .:../v1 Test1
-1
But if Test1.java
针对新的类层次结构重新编译,它的行为将会改变。本质上就是这样Test2.java
是,但具有不同的名称,以便我们可以轻松地看到运行旧二进制文件和重新编译版本之间的区别。