【发布时间】:2010-11-20 13:37:59
【问题描述】:
是否有任何 Java API 可以找出编译类文件的 JDK 版本?当然有 javap 工具可以找到here 中提到的主要版本。但是我想以编程方式进行,以便我可以警告用户为适当的 JDK 编译它
【问题讨论】:
-
涉及从文件读取字节的答案对我来说似乎很不文明。应该有一种方法可以使用反射来获取这些信息,例如 Foobar.class.getTargetVersion()。
是否有任何 Java API 可以找出编译类文件的 JDK 版本?当然有 javap 工具可以找到here 中提到的主要版本。但是我想以编程方式进行,以便我可以警告用户为适当的 JDK 编译它
【问题讨论】:
JavaP 确实有一个 API,但它是特定于 Sun JDK 的。
它位于tools.jar,在sun/tools/javap/Main.class 下。
【讨论】:
import java.io.*;
public class ClassVersionChecker {
public static void main(String[] args) throws IOException {
for (int i = 0; i < args.length; i++)
checkClassVersion(args[i]);
}
private static void checkClassVersion(String filename)
throws IOException
{
DataInputStream in = new DataInputStream
(new FileInputStream(filename));
int magic = in.readInt();
if(magic != 0xcafebabe) {
System.out.println(filename + " is not a valid class!");;
}
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
System.out.println(filename + ": " + major + " . " + minor);
in.close();
}
}
可能的值是:
major minor Java platform version
45 3 1.0
45 3 1.1
46 0 1.2
47 0 1.3
48 0 1.4
49 0 5
50 0 6
51 0 7
52 0 8
53 0 9
54 0 10
55 0 11
56 0 12
57 0 13
58 0 14
【讨论】:
这将为您获取类文件的内容:
MysteryClass.class.getResourceAsStream("MysteryClass.class")
然后查看字节 5-8 以获取次要版本和主要版本。可以在here 找到这些数字和 JDK 版本之间的映射。
【讨论】:
直接读取类文件即可。很容易找出版本。查看spec 和wiki,然后尝试代码。包装此代码并使其更有用/更漂亮留作练习。或者,您可以使用 BCEL、ASM 或 JavaAssist 之类的库
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ClassVersionTest
{
private static final int JAVA_CLASS_MAGIC = 0xCAFEBABE;
public static void main(String[] args)
{
try
{
DataInputStream dis = new DataInputStream(new FileInputStream("Test.class"));
int magic = dis.readInt();
if(magic == JAVA_CLASS_MAGIC)
{
int minorVersion = dis.readUnsignedShort();
int majorVersion = dis.readUnsignedShort();
/**
* majorVersion is ...
* J2SE 6.0 = 50 (0x32 hex),
* J2SE 5.0 = 49 (0x31 hex),
* JDK 1.4 = 48 (0x30 hex),
* JDK 1.3 = 47 (0x2F hex),
* JDK 1.2 = 46 (0x2E hex),
* JDK 1.1 = 45 (0x2D hex).
*/
System.out.println("ClassVersionTest.main() " + majorVersion + "." + minorVersion);
}
else
{
// not a class file
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
【讨论】:
正如其他人所展示的,通过读取类文件的前 8 个字节很容易做到这一点。如果你想要一个预建的二进制库,你可以下载一个here。
【讨论】:
Apache BCEL 提供此 API:
JavaClass c = Repository.lookupClass("com.x.MyClass")
c.getMinor();
c.getMajor();
【讨论】:
basszero 的方法可以通过 UNIX 命令行和“od(1)”命令完成:
% od -x HelloWorldJava.class |head -2
0000000 feca beba 0000 3100 dc00 0007 0102 2a00
0000020 6f63 2f6d 6e65 6564 6163 642f 6d65 2f6f
“feca beba”是magic number。 “0000 3100”是0x31,代表J2SE 5.0。
【讨论】:
在 Linux 上,您可以在类文件上使用 file 命令,我发现这对我的用例来说最简单。例如:
$ file Foo.class
Foo.class: compiled Java class data, version 50.0 (Java 1.6)
【讨论】:
我在 Windows 上的批处理文件中使用此脚本,重定向输出并 grep 我正在验证的主要号码:
for /R %%f in (*.class) do (
"C:\Program Files\Java\JDK8\bin\javap" -v "%%f" | findstr major )
我是这样运行的:
verify.bat > versionResults.txt
【讨论】: