什么版本的javac构build我的jar?

我怎么知道用什么版本的Java编译器来构build一个jar? 我有一个jar文件,它可能已经build立在三个JDK中的任何一个。 我们需要知道哪一个,所以我们可以certificate兼容性。 编译器版本是embedded在类文件或jar的某处吗?

您无法从JAR文件本身中得知。

下载一个hex编辑器并打开JAR中的一个类文件,查看4到7的字节偏移量。版本信息是内置的。

http://en.wikipedia.org/wiki/Java_class_file

注意:正如下面的评论所述,

那些字节告诉你什么版本的类已经被编译FOR,而不是什么版本编译它。

一个jar只是一个容器。 这是一个文件存档ā拉tar 。 虽然jar可能在META-INF层次结构中包含有趣的信息,但它没有义务指定其内容中类的年份。 为此,必须检查其中的class文件。

正如Peter Lawrey在对原始问题的评论中所提到的那样,您不一定知道哪个JDK版本创build了一个给定的class文件,但是您可以find包含在jar中的class文件的字节码类版本。

是的,这有点糟糕,但第一步是从jar提取一个或多个类。 例如:

 $ jar xf log4j-1.2.15.jar 

在安装了Cygwin的 Linux,Mac OS X或Windows上, 文件(1)命令知道类的版本。

 $ file ./org/apache/log4j/Appender.class ./org/apache/log4j/Appender.class: compiled Java class data, version 45.3 

或者,从@ jikes.thunderbolt的JDK中使用javap恰当地指出:

 $ javap -v ./org/apache/log4j/Appender.class | grep major major version: 45 

而且如果你没有使用file或者grep其归入Windows环境

 > javap -v ./org/apache/log4j/Appender.class | findstr major major version: 45 

FWIW,我会同意javap会告诉更多关于一个给定的class文件比原来的问题。

无论如何,一个不同的类版本,例如:

 $ file ~/bin/classes/P.class /home/dave/bin/classes/P.class: compiled Java class data, version 50.0 

类版本主号对应于以下Java JDK版本:

  • 45.3 = Java 1.1
  • 46 = Java 1.2
  • 47 = Java 1.3
  • 48 = Java 1.4
  • 49 = Java 5
  • 50 = Java 6
  • 51 = Java 7
  • 52 = Java 8
  • 53 = Java 9

这是Javafind这些信息的方法。

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

例如:
> javap -v Application | findstr major major version: 51

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

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

就我所知,编译器本身并不插入任何识别签名。 无论如何,我无法在VM规格类格式中find这样的东西。

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代码,以检查每个依赖项的编译情况。

一个class轮(Linux)

unzip -p mylib.jar META-INF/MANIFEST.MF

这将MANIFEST.MF文件的内容打印到标准输出(希望在您的jar文件中有一个:)

根据构build包的内容,您可以在“ Created-By或“ Build-Jdk键中findJDK版本。

没有必要解压缩JAR(如果其中一个类名是已知的,或者使用7zip查找),所以在Windows上,以下就足够了:

 javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major 

运行Bash的开发人员和pipe理员可能会发现这些便利function很有用:

 jar_jdk_version() { [[ -n "$1" && -x "`command -v javap`" ]] && javap -classpath "$1" -verbose $(jar -tf "$1" | grep '.class' | head -n1 | sed -e 's/\.class$//') | grep 'major version' | sed -e 's/[^0-9]\{1,\}//' } print_jar_jdk_version() { local version version=$(jar_jdk_version "$1") case $version in 49) version=1.5;; 50) version=1.6;; 51) version=1.7;; 52) version=1.8;; esac [[ -n "$version" ]] && echo "`basename "$1"` contains classes compiled with JDK version $version." } 

您可以将它们粘贴到一次性使用中,或将它们添加到~/.bash_aliases~/.bashrc 。 结果如下所示:

 $ jar_jdk_version poi-ooxml-3.5-FINAL.jar 49 

 $ print_jar_jdk_version poi-ooxml-3.5-FINAL.jar poi-ooxml-3.5-FINAL.jar contains classes compiled with JDK version 1.5. 

编辑由于jackrabbit指出,你不能100%依靠清单告诉你任何有用的东西。 如果是这样,那么你可以用你最喜欢的UNIX shell unzip

 $ unzip -pa poi-ooxml-3.5-FINAL.jar META-INF/MANIFEST.MF Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 11.3-b02 (Sun Microsystems Inc.) Built-By: yegor Specification-Title: Apache POI Specification-Version: 3.5-FINAL-20090928 Specification-Vendor: Apache Implementation-Title: Apache POI Implementation-Version: 3.5-FINAL-20090928 Implementation-Vendor: Apache 

这个.jar在关于包含类的清单中没有任何用处。

每个类文件都有一个为字节代码级别embedded的版本号,JVM用它来查看它是否喜欢那个特定的字节代码块。 Java 1.4为48,Java 1.5为49,Java 6为50。

存在许多编译器,可以在每个级别生成字节码,javac使用“-target”选项指示要生成哪个字节码级别,Java 6 javac可以生成至less为1.4,1.5和6的字节码。相信编译器会插入任何可以识别编译器本身的东西,这是我想要的。 另外,Eclipse编译器越来越多地被使用,因为它是一个只能运行JRE的jar。

在jar文件中通常有很多类,每个类都是独立的,所以你需要调查jar中的所有类,以确定内容的特征。

继续@David J. Liszewski的回答,我运行了下面的命令在Ubuntu上提取jar文件的清单:

 # Determine the manifest file name: $ jar tf LuceneSearch.jar | grep -i manifest META-INF/MANIFEST.MF # Extract the file: $ sudo jar xf LuceneSearch.jar META-INF/MANIFEST.MF # Print the file's contents: $ more META-INF/MANIFEST.MF Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.2 Created-By: 1.7.0_25-b30 (Oracle Corporation) Main-Class: org.wikimedia.lsearch.config.StartupManager 

要扩展Jonathon Faust和McDowell的答案:如果你使用的是基于* nix的系统,你可以使用od (最早的Unix程序之一,几乎到处都可用)来查询.class文件的二进制级别:

 od -An -j7 -N1 -t dC SomeClassFile.class 

这将输出熟悉的整数值,例如对于Java 550 ,对于Java 651等等。

1引自https://en.wikipedia.org/wiki/Od_(Unix);

在Windows上执行以下操作:

  1. 使用WinZip / Java JAR命令解压缩或解压缩JAR文件。
  2. 将其中一个类文件拖放到您的Eclipse Java项目中。
  3. 打开类文件。

现在Eclipse将显示确切的主要和次要版本。

我build立一个基于戴维斯build议使用file命令一个小的bash脚本(在github上)

很多时候,您可能正在查看整个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将能够加载这些类,这可能是你想要开始的。