Unsupported major.minor version 51.0的解决方法
一直以来都是用jdk1.5,这次重返电信由于其系统是在jdk1.4上编译的,编译的时候出现了unsupported major.minor version49.0的错误,上网查看了一下还是一个很普遍的错误,捣鼓了两天终于捣鼓出一些东西,现分享给大家。何谓 major.minor,且又居身于何处呢?先感性认识并找到 major.minor 来。顺便写一段 代码,然后用 JDK 1.5 的编译器编译成class,用UltraEdit或者其他能打开非十进制文件的软件打开此class,见下图:
[attach]3779[/attach]
从上图中我们看出来了什么是 major.minor version 了,它相当于一个软件的主次版本号,只是在这里是标识的一个 Java Class 的主版本号和次版本号,同时我们看到 minor_version 为 0x0000,major_version 为 0x0031,转换为十制数分别为0 和 49,即 major.minor 就是 49.0 了。
现在不妨从 JDK 1.1 到 JDK 1.7 编译器编译出的 class 的默认 minor.major version 吧。(又走到 Sun 的网站上翻腾出我从来都没用过的古董来)
[table=98%]
[tr][td=1,1,20%][b]JDK 编译器版本[/b][/td][td=1,1,30%][b]target 参数[/b][/td][td=1,1,25%][b]十六进制 minor.major[/b][/td][td=1,1,25%][b]十进制 minor.major[/b][/td][/tr]
[tr][td][b]jdk1.1.8[/b][/td][td][b]不能带 target 参数[/b][/td][td][b]00 03 00 2D[/b][/td][td][b]45.3[/b][/td][/tr]
[tr][td][b]jdk1.2.2[/b][/td][td][b]不带(默认为 -target 1.1)[/b][/td][td][b]00 03 00 2D[/b][/td][td][b]45.3[/b][/td][/tr]
[tr][td][b]jdk1.2.2[/b][/td][td][b]-target 1.2[/b][/td][td][b]00 00 00 2E[/b][/td][td][b]46.0[/b][/td][/tr]
[tr][td][b]jdk1.3.1_19[/b][/td][td][b]不带(默认为 -target 1.1)[/b][/td][td][b]00 03 00 2D[/b][/td][td][b]45.3[/b][/td][/tr]
[tr][td][b]jdk1.3.1_19[/b][/td][td][b]-target 1.3[/b][/td][td][b]00 00 00 2F[/b][/td][td][b]47.0[/b][/td][/tr]
[tr][td][b]j2sdk1.4.2_10[/b][/td][td][b]不带(默认为 -target 1.2)[/b][/td][td][b]00 00 00 2E[/b][/td][td][b]46.0[/b][/td][/tr]
[tr][td][b]j2sdk1.4.2_10[/b][/td][td][b]-target 1.4[/b][/td][td][b]00 00 00 30[/b][/td][td][b]48.0[/b][/td][/tr]
[tr][td][b]jdk1.5.0_11[/b][/td][td][b]不带(默认为 -target 1.5)[/b][/td][td][b]00 00 00 31[/b][/td][td][b]49.0[/b][/td][/tr]
[tr][td][b]jdk1.5.0_11[/b][/td][td][b]-target 1.4 -source 1.4[/b][/td][td][b]00 00 00 30[/b][/td][td][b]48.0[/b][/td][/tr]
[tr][td][b]jdk1.6.0_01[/b][/td][td][b]不带(默认为 -target 1.6)[/b][/td][td][b]00 00 00 32[/b][/td][td][b]50.0[/b][/td][/tr]
[tr][td][b]jdk1.6.0_01[/b][/td][td][b]-target 1.5[/b][/td][td][b]00 00 00 31[/b][/td][td][b]49.0[/b][/td][/tr]
[tr][td][b]jdk1.6.0_01[/b][/td][td][b]-target 1.4 -source 1.4[/b][/td][td][b]00 00 00 30[/b][/td][td][b]48.0[/b][/td][/tr]
[tr][td][b]jdk1.7.0[/b][/td][td][b]不带(默认为 -target 1.6)[/b][/td][td][b]00 00 00 32[/b][/td][td][b]50.0[/b][/td][/tr]
[tr][td][b]jdk1.7.0[/b][/td][td][b]-target 1.7[/b][/td][td][b]00 00 00 33[/b][/td][td][b]51.0[/b][/td][/tr]
[tr][td][b]jdk1.7.0[/b][/td][td][b]-target 1.4 -source 1.4[/b][/td][td][b]00 00 00 30[/b][/td][td][b]48.0[/b][/td][/tr]
[tr][td][b]Apache Harmony 5.0M3[/b][/td][td][b]不带(默认为 -target 1.2)[/b][/td][td][b]00 00 00 2E[/b][/td][td][b]46.0[/b][/td][/tr]
[tr][td][b]Apache Harmony 5.0M3[/b][/td][td][b]-target 1.4[/b][/td][td][b]00 00 00 30[/b][/td][td][b]48.0[/b][/td][/tr]
[/table] 当然你也可以用其他方法查看版本号,比如javap -verbose XXXX(class名)。
那么现在如果碰到这种问题该知道如何解决了吧,还会像我所见到有些兄弟那样,去找个 1.4 的 JDK 下载安装,然后用其重新编译所有的代码吗?且不说这种方法的繁琐,而且web应用程序还不一定能成功,其实大可不必如此费神,我们一定还记得 javac 还有个 -target 参数,对啦,可以继续使用 1.5 JDK,编译时带上参数 -target 1.4 -source 1.4 就 OK 啦,不过你一定要对哪些 API 是 1.5 JDK 加入进来的了如指掌,不能你的 class 文件拿到 JVM 1.4 下就会 method not found。目标 JVM 是 1.3 的话,编译选项就用 -target 1.3 -source 1.3 了。
相应的如果使用 ant ,它的 javac 任务也可对应的选择 target 和 source
<javac target="1.4" source="1.4" ............................/>
如果是在开发中,可以肯定的是现在真正算得上是 JAVA IDE 对于工程也都有编译选项设置目标代码的。例如 Eclipse 的项目属性中的 Java Compiler 设置,如图:
[attach]3780[/attach]
其实理解 major.minor 就像是我们可以这么想像,同样是微软件的程序,32 位的应用程序不能拿到 16 位系统中执行那样。
如果我们发布前了解到目标 JVM 版本,知道怎么从 java class 文件中看出 major.minor 版本来,就不用等到服务器报出异常才着手去解决,也就能预知到可能发生的问题。
其他时候遇到这个问题应具体解决,总之问题的根由是低版本的 JVM 无法加载高版本的 class 文件造成的,找到高版本的 class 文件处理一下就行了。
解决Unsupported major.minor version 51.0问题的感悟
今天偶然间同事遇到一个问题,也加深了自己对eclipse中build path和java compiler compliance level的理解。问题是这样的,同事在eclipse中开发的项目,导成jar之后,放到服务器上,总是报“Unsupported major.minor version 51.0”的错误,从网上查,一直说是JDK的问题,但是就不是很清楚怎么回事,怎么解决,最后,经过另一个同事,终于解决了,也使我终于明白了问题的来龙去脉:在eclipse中开发的项目有个java build path中可以配置的jdk,还有个java compiler中可以配置compiler level,这两个是有区别的,build path的JDK版本是你开发的时候编译器需要使用到的,就是你在eclipse中开发代码,给你提示报错的,编译的过程;java compiler compliance level中配置的编译版本号,这个编译版本号的作用是,你这个项目将来开发完毕之后,要放到服务器上运行,那个服务器上JDK的运行版本。同事的问题就是,build path中配置1.7的JDK,java compiler compliance level中配置的1.7,但是服务器上是1.6的JDK,就报了那个错误,说是编译所用的jdk(1.7)比运行所用的jdk(1.6)高了,这是错误的。
总结:build path的JDK版本是你开发的时候编译器需要使用到的,例如,如果用的JDK1.4就不能使用泛型。而java compiler compliance level设置的是你写好的JAVA代码按照什么JDK版本级别编译,例如:设置的是1.4,编译出来的class文件可以在1.4以上的JRE上运行,如果用的是5.0级别编译,就不能运行在1.4的环境里面,会提示版本过高。
补充:后经实例证明,在eclipse中进行开发的时候,build path 中JDK进行类库的编译(就是你使用类在不在这个JDK中),java compiler compliance level是对这个项目语法的编译(就是你的项目中语法的正确与否),在开发的过程中,这两个地方是都起作用的。所以说,最最安全的做法,是build path 和 java complier compliance level和服务器配置的JDK都保持一致,就不会出现任何问题的。 辛苦辛苦,谢谢了~~
bjcars.net 努力~~各位。。。
bjcars.net
页:
[1]