我如何知道哪个版本的Java编译器被用来构建一个jar?我有一个jar文件,它可以构建在三个jdk中的任何一个中。我们需要确切知道是哪一个,这样我们才能证明兼容性。编译器版本是否嵌入到类文件或jar中?
当前回答
您可以通过检查前8个字节(或使用可以的应用程序)来判断Java二进制版本。
据我所知,编译器本身并没有插入任何标识签名。无论如何,我不能在文件VM规范类格式中发现这样的东西。
其他回答
每个类文件都嵌入了字节代码级别的版本号,JVM使用该版本号来查看它是否喜欢特定的字节代码块。Java 1.4是48,Java 1.5是49,Java 6是50。
有许多编译器可以在每个级别生成字节代码,javac使用“-target”选项来指示要生成哪个字节代码级别,Java 6 javac可以生成至少1.4、1.5和6级的字节代码。我不相信编译器插入任何可以识别编译器本身,这是我认为你要求的。Eclipse编译器也越来越多地被使用,因为它是一个单独的jar,只能与JRE一起运行。
在jar文件中通常有许多类,并且每个类都是独立的,因此您需要研究jar中的所有类,以确定内容的特征。
罐子只是一个容器。它是一个文件归档文件(ā la tar或zip)。虽然jar可能在其META-INF层次结构中包含有趣的信息,但它没有义务指定其内容中的类的年份。为此,必须检查其中的类文件。
正如Peter Lawrey在对原始问题的评论中提到的,您不一定知道哪个JDK版本构建了给定的类文件,但您可以找到jar中包含的类文件的字节码类版本。
是的,这有点糟糕,但第一步是从罐子中提取一个或多个类。例如:
$ jar xf log4j-1.2.15.jar
在安装了Cygwin的Linux、Mac OS X或Windows上,file(1)命令知道类版本。
$ file ./org/apache/log4j/Appender.class
./org/apache/log4j/Appender.class: compiled Java class data, version 45.3
或者,使用JDK中的javap作为@jikes。Thunderbolt恰当地指出:
$ javap -v ./org/apache/log4j/Appender.class | grep major
major version: 45
对于没有文件或grep的Windows环境
> javap -v ./org/apache/log4j/Appender.class | findstr major
major version: 45
FWIW,我同意javap会告诉一个给定的类文件比最初的问题更多的信息。
总之,一个不同的类版本,例如:
$ file ~/bin/classes/P.class
/home/dave/bin/classes/P.class: compiled Java class data, version 50.0
下面的列表显示了类版本的主版本号和引入类主版本的JDK版本。
注意:类版本不一定标识用于编译类的JDK -它只标识可能生成该类的最早版本。
例如,类主版本52可以由Java 7之后的任何JDK生成。
45.3 = Java 1.1 46 = Java 1.2 47 = Java 1.3 48 = java1.4 49 = Java 5 50 = Java 6 51 = Java 7 52 = Java 8 53 = Java 9 54 = Java 10 55 = Java 11 56 = Java 12 57 = Java 13 58 = Java 14 59 = Java 15 60 = Java 16 61 = Java 17 62 = Java 18 63 = Java 19
您不一定能从JAR文件本身判断出来。
下载一个十六进制编辑器,打开JAR中的一个类文件,查看字节偏移量4到7。版本信息是内置的。
http://en.wikipedia.org/wiki/Java_class_file
注:如以下评论所述,
这些字节告诉你类是为哪个版本编译的,而不是 哪个版本编译了它。
我也写了自己的bash脚本来转储所有在命令行传递的jar所需的Java版本…我的有点粗糙,但适合我;-)
示例使用
$ jar_dump_version_of_jvm_required.sh *.jar
JVM VERSION REQUIRED: 46.0, /private/tmp/jars/WEB-INF/lib/json-simple-1.1.jar
JVM VERSION REQUIRED: 49.0, /private/tmp/jars/WEB-INF/lib/json-smart-1.1.1.jar
JVM VERSION REQUIRED: 50.0, /private/tmp/jars/WEB-INF/lib/jsontoken-1.0.jar
JVM VERSION REQUIRED: 50.0, /private/tmp/jars/WEB-INF/lib/jsr166y-1.7.0.jar
jar_dump_version_of_jvm_required.sh
#!/bin/bash
DIR=$(PWD)
function show_help()
{
ME=$(basename $0)
IT=$(cat <<EOF
Dumps the version of the JVM required to run the classes in a jar file
usage: $ME JAR_FILE
e.g.
$ME myFile.jar -> VERSION: 50.0 myFile.jar
Java versions are:
54 = Java 10
53 = Java 9
52 = Java 8
51 = Java 7
50 = Java 6
49 = Java 5
48 = Java 1.4
47 = Java 1.3
46 = Java 1.2
45.3 = Java 1.1
EOF
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
function unzipJarToTmp()
{
JAR=$1
CLASS_FILE=$(jar -tf "$JAR" | grep \.class$ | grep -v '\$' | head -n1 | awk '{print $NF}')
OUT_FILE="$CLASS_FILE"
#echo "J=$JAR C=$CLASS_FILE O=$OUT_FILE"
jar xf "$JAR" "$CLASS_FILE"
MAJOR=$(javap -v "$OUT_FILE" 2>&1 | grep major | awk -F' ' '{print $3'})
MINOR=$(javap -v "$OUT_FILE" 2>&1 | grep minor | awk -F' ' '{print $3'})
if [ -z "$MAJOR" ]
then
echo "JVM VERSION REQUIRED: NA as no classes in $JAR"
else
echo "JVM VERSION REQUIRED: $MAJOR.$MINOR, $JAR"
fi
}
# loop over cmd line args
for JAR in "$@"
do
cd "$DIR"
JAR_UID=$(basename "$JAR" | sed s/.jar//g)
TMPDIR=/tmp/jar_dump/$JAR_UID/
mkdir -p "$TMPDIR"
JAR_ABS_PATH=$(realpath $JAR)
cd "$TMPDIR"
#echo "$JAR_ABS_PATH"
unzipJarToTmp "$JAR_ABS_PATH"
#sleep 2
done
不需要解包JAR(如果其中一个类名已知或被查找,例如使用7zip),因此在Windows上,以下步骤就足够了:
javap -cp log4j-core-2.5.jar -verbose org.apache.logging.log4j.core.Logger | findstr major
推荐文章
- 如何格式化Joda-Time DateTime仅为mm/dd/yyyy?
- 如何在POM.xml中引用环境变量?
- 如何在android中复制一个文件?
- 将整数转换为字符串,以逗号表示千
- 接口方法的最终参数-有什么意义?
- Java中的@UniqueConstraint注释
- 如何在清洁模式下运行eclipse ?如果我们这样做会发生什么?
- 获取java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory异常
- Java中的正则表达式命名组
- c#和Java的主要区别是什么?
- 什么是NullPointerException,我如何修复它?
- 在Java中使用“final”修饰符
- 无法在Flutter上找到捆绑的Java版本
- 如何在Kotlin解析JSON ?
- 如何在新的材质主题中改变背面箭头的颜色?