0%

3个JDK最好一致

3个JDK(源码所使用JDK,目标运行平台JDK,编译所使用JDK)最好一致,以避免一些奇怪的异常或者错误。

一、3个JDK不一致导致抛出NoClassDefFoundError异常的一种情形

实验代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {

ConcurrentHashMap<String, AtomicInteger> domainCounts = new ConcurrentHashMap();

public static void main(String[] args) {
Main main = new Main();
main.f();
}

public void f() {
for (Iterator iterator = domainCounts.keySet().iterator(); ((Iterator)iterator).hasNext();) {
String val = (String)iterator.next();

System.out.println(val);
}
}
}

编译命令为~/jdk1.8/bin/javac -source 1.6 -target 1.6 Main.java,运行命令为~/jdk1.6/bin/java Main,抛出异常如下:

1
2
3
Exception in thread "main" java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
at Main.f(Main.java:15)
at Main.main(Main.java:11)

执行javap -v Main命令,发现f()方法对应的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void f();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: getfield #4 // Field domainCounts:Ljava/util/concurrent/ConcurrentHashMap;
4: invokevirtual #8 // Method java/util/concurrent/ConcurrentHashMap.keySet:()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
7: invokevirtual #9 // Method java/util/concurrent/ConcurrentHashMap$KeySetView.iterator:()Ljava/util/Iterator;
10: astore_1
11: aload_1
12: invokeinterface #10, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
17: ifeq 40
20: aload_1
21: invokeinterface #11, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
26: checkcast #12 // class java/lang/String
29: astore_2
30: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_2
34: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
37: goto 11
40: return
LineNumberTable:
line 15: 0
line 16: 20
line 18: 30
line 19: 37
line 20: 40
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 11
locals = [ class java/util/Iterator ]
frame_type = 250 /* chop */
offset_delta = 28

查看上述内容,可发现绑定到了属于JDK1.8的java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView,从而可知在使用JDK1.8编译的时候,一些特定于JDK1.8的依赖信息被写入到了CLASS文件中(笔者认为这是JDK1.8中javac命令实现的bug,因为我们指定了-target 1.6,自然期待的结果应该是特定于JDK1.6的依赖信息被写入到CLASS文件中),这最终导致了当运行于JDK1.6目标平台时会抛出java.lang.NoClassDefFoundError异常。

您的支持将鼓励我继续分享!