【问题标题】:Java API to find out the JDK version a class file is compiled for?Java API找出编译类文件的JDK版本?
【发布时间】:2010-11-20 13:37:59
【问题描述】:

是否有任何 Java API 可以找出编译类文件的 JDK 版本?当然有 javap 工具可以找到here 中提到的主要版本。但是我想以编程方式进行,以便我可以警告用户为适当的 JDK 编译它

【问题讨论】:

  • 涉及从文件读取字节的答案对我来说似乎很不文明。应该有一种方法可以使用反射来获取这些信息,例如 Foobar.class.getTargetVersion()。

标签: version java


【解决方案1】:

JavaP 确实有一个 API,但它是特定于 Sun JDK 的。

它位于tools.jar,在sun/tools/javap/Main.class 下。

【讨论】:

    【解决方案2】:
    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
    

    【讨论】:

      【解决方案3】:

      这将为您获取类文件的内容:

      MysteryClass.class.getResourceAsStream("MysteryClass.class")

      然后查看字节 5-8 以获取次要版本和主要版本。可以在here 找到这些数字和 JDK 版本之间的映射。

      【讨论】:

      • 字符串参数是否需要完全限定? getResourceAsStream("org/apache/foobar/Whatever.class")?
      • 不,因为您使用类本身作为获取资源的基础。如果您可以获取 ClassLoader 的 Resource 方法而不是类,则需要完全限定名称。
      【解决方案4】:

      直接读取类文件即可。很容易找出版本。查看specwiki,然后尝试代码。包装此代码并使其更有用/更漂亮留作练习。或者,您可以使用 BCELASMJavaAssist 之类的库

      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();
              }
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        正如其他人所展示的,通过读取类文件的前 8 个字节很容易做到这一点。如果你想要一个预建的二进制库,你可以下载一个here

        【讨论】:

          【解决方案6】:

          Apache BCEL 提供此 API:

          JavaClass c = Repository.lookupClass("com.x.MyClass")
          c.getMinor();
          c.getMajor();
          

          【讨论】:

            【解决方案7】:

            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。

            【讨论】:

              【解决方案8】:

              在 Linux 上,您可以在类文件上使用 file 命令,我发现这对我的用例来说最简单。例如:

              $ file Foo.class
              Foo.class: compiled Java class data, version 50.0 (Java 1.6)
              

              【讨论】:

                【解决方案9】:

                我在 Windows 上的批处理文件中使用此脚本,重定向输出并 grep 我正在验证的主要号码:

                for /R %%f in (*.class) do (
                "C:\Program Files\Java\JDK8\bin\javap" -v "%%f" | findstr major )
                

                我是这样运行的:

                verify.bat > versionResults.txt
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-01-27
                  • 2022-01-23
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多