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
异常。