关于jvm字节码:用于读取和显示Java .class版本的工具

Tool to read and display Java .class versions

你们中没有人知道将搜索.class文件然后显示其编译版本的工具吗?

我知道您可以在十六进制编辑器中单独查看它们,但是我要查看很多类文件(由于某种原因,我的大型应用程序中的某些内容正在编译为Java6)。


使用JDK随附的javap工具。 -verbose选项将打印类文件的版本号。

1
2
3
4
5
6
7
> javap -verbose MyClass
Compiled from"MyClass.java"
public class MyClass
  SourceFile:"MyClass.java"
  minor version: 0
  major version: 46
...

仅显示版本:

1
2
WINDOWS> javap -verbose MyClass | find"version"
LINUX  > javap -verbose MyClass | grep version

无需第三方API即可轻松读取类文件签名并获取这些值。您需要做的就是读取前8个字节。

1
2
3
4
ClassFile {
    u4 magic;
    u2 minor_version;
    u2 major_version;

对于51.0版的类文件(Java 7),起始字节为:

1
CA FE BA BE 00 00 00 33

...其中0xCAFEBABE是魔术字节,0x0000是次要版本,0x0033是主要版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.*;

public class Demo {
  public static void main(String[] args) throws IOException {
    ClassLoader loader = Demo.class.getClassLoader();
    try (InputStream in = loader.getResourceAsStream("Demo.class");
        DataInputStream data = new DataInputStream(in)) {
      if (0xCAFEBABE != data.readInt()) {
        throw new IOException("invalid header");
      }
      int minor = data.readUnsignedShort();
      int major = data.readUnsignedShort();
      System.out.println(major +"." + minor);
    }
  }
}

遍历目录(文件)和档案(JarFile)查找类文件是微不足道的。

Oracle的Joe Darcy的博客列出了从Java到Java 7的类版本到JDK版本的映射:

1
2
3
4
5
6
7
8
9
10
Target   Major.minor Hex
1.1      45.3        0x2D
1.2      46.0        0x2E
1.3      47.0        0x2F
1.4      48.0        0x30
5 (1.5)  49.0        0x31
6 (1.6)  50.0        0x32
7 (1.7)  51.0        0x33
8 (1.8)  52.0        0x34
9        53.0        0x35


在类Unix上

1
file /path/to/Thing.class

还将提供文件类型和版本。输出如下所示:

compiled Java class data, version 49.0


如果您使用的是Unix系统,则可以执行

1
find /target-folder -name \*.class | xargs file | grep"version 50\.0"

(我的文件版本对Java6类说"编译的Java类数据,版本50.0")。


另一个Java版本检查

1
od -t d -j 7 -N 1 ApplicationContextProvider.class | head -1 | awk '{print"Java", $2 - 44}'

在月食中,如果您没有附加源。注意附加源按钮后的第一行。

//从CDestinoLog.java编译(版本1.5:49.0,超级位)

enter image description here


也许这也对某人有帮助。看起来有一种更简单的方法来获取用于编译/构建.class的JAVA版本。这种方式对于JAVA版本的应用程序/类自检很有用。

我遍历了JDK库,发现了这个有用的常量:
com.sun.deploy.config.BuiltInProperties.CURRENT_VERSION。
我不知道它何时在JAVA JDK中。

尝试使用这段代码获取多个版本常量,结果如下:

src:

1
2
3
4
5
System.out.println("JAVA DEV       ver.:" + com.sun.deploy.config.BuiltInProperties.CURRENT_VERSION);
System.out.println("JAVA RUN     v. X.Y:" + System.getProperty("java.specification.version") );
System.out.println("JAVA RUN v. W.X.Y.Z:" + com.sun.deploy.config.Config.getJavaVersion() ); //_javaVersionProperty
System.out.println("JAVA RUN  full ver.:" + System.getProperty("java.runtime.version")  +" (may return unknown)" );
System.out.println("JAVA RUN       type:" + com.sun.deploy.config.Config.getJavaRuntimeNameProperty() );

输出:

1
2
3
4
5
JAVA DEV       ver.: 1.8.0_77
JAVA RUN     v. X.Y: 1.8
JAVA RUN v. W.X.Y.Z: 1.8.0_91
JAVA RUN  full ver.: 1.8.0_91-b14 (may return unknown)
JAVA RUN       type: Java(TM) SE Runtime Environment

在类字节码中确实存储有常量-请参见Main.call中红色标记的部分-存储在.class字节码中的常量

常量在类中,用于检查JAVA版本是否已过期(请参阅Java如何检查已过期)...


推荐阅读