我如何知道哪个版本的Java编译器被用来构建一个jar?我有一个jar文件,它可以构建在三个jdk中的任何一个中。我们需要确切知道是哪一个,这样我们才能证明兼容性。编译器版本是否嵌入到类文件或jar中?


当前回答

Owen发布的代码可以告诉你一些其他答案中提到的信息:

public void simpleExample ()
{
    FileInputStream fis = new FileInputStream ("mytest.class");
    parseJavaClassFile ( fis );
}
protected void parseJavaClassFile ( InputStream classByteStream ) throws Exception
{
    DataInputStream dataInputStream = new DataInputStream ( classByteStream );
    magicNumber = dataInputStream.readInt();
    if ( magicNumber == 0xCAFEBABE )
    {
        int minorVer = dataInputStream.readUnsignedShort();
        int majorVer = dataInputStream.readUnsignedShort();
        // do something here with major & minor numbers
    }
}

也可以看看这个和这个网站。最后,我迅速修改了Mind Products代码,以检查我的每个依赖项是为了什么而编译的。

其他回答

下面是Java查找这些信息的方法。

Windows: javap -v <class> | findstr major Unix: javap -v <class> | grep major

例如: > javap -v应用程序| findstr major 主要版本:51

基于现有的答案,我试图构建一些更方便的东西,应该在大多数操作系统上工作(这取决于cat, xxd和awk),你只需要把你的类文件名从你的jar中提取出来。

cat YOUR_FILE.class | xxd -s 7 -l1 | awk  '{print $2}' | sed -e 's/34/Java SE 8/' -e 's/35/Java SE 9/' -e 's/36/Java SE 10/' -e 's/37/Java SE 11/' -e 's/38/Java SE 12/' -e 's/39/Java SE 13/' -e 's/3a/Java SE 14/' -e 's/3b/Java SE 15/' -e 's/3c/Java SE 16/' -e 's/3d/Java SE 17/' -e 's/3e/Java SE 18/'

方便的映射到人类可读的版本适用于Java 8开始的主要版本。(否则你会得到主版本的普通十六进制版本号,参见1中的链接。对于一个定义)

这个小脚本是基于什么:

我使用类文件的内容,并使用xxd获取第7个字节。 根据定义,这是用于主要版本的,参见维基百科: https://en.wikipedia.org/wiki/Java_class_file 然后我只是用一个列表代替所有版本值开始的十六进制34 java 8和结束的十六进制3e java 18。

很多时候,您可能会查看整个jar文件,或者除了它们本身之外还包含许多jar文件的war文件。

因为我不想手动检查每个类,所以我写了一个java程序来做到这一点:

https://github.com/Nthalk/WhatJDK

./whatjdk some.war
some.war:WEB-INF/lib/xml-apis-1.4.01.jar contains classes compatible with Java1.1
some.war contains classes compatible with Java1.6

虽然这并没有说明类是用什么编译的,但它决定了哪些JDK能够加载这些类,这可能是您想要开始的。

您可以通过检查前8个字节(或使用可以的应用程序)来判断Java二进制版本。

据我所知,编译器本身并没有插入任何标识签名。无论如何,我不能在文件VM规范类格式中发现这样的东西。

Java编译器(javac)不构建jar,它将Java文件转换为类文件。Jar工具(Jar)创建实际的Jar。如果没有指定自定义清单,默认清单将指定使用哪个版本的JDK来创建jar。