seraphyの日記

日記というよりは過去を振り返るときのための単なる備忘録

コンパイルされたクラスファイルのターゲットとしていたJavaVMのバージョンを確認する方法

動機

たとえば、コレクションクラスを使っているのにジェネリックでないソースと、そのコンパイル済みのクラスファイルをもらったとする。
日付は2010年あたりになっている。
書き方や使っているクラスからみて、もともとは、かなり古いソースと見受けられる。
だが、はたして、最後にコンパイルしたとき、これは、どのバージョンのJAVAを想定して作ったものであろうか?

確認方法

JDK付属のjavapツールを使う事でクラスファイルに埋め込まれたターゲットのバージョンを確認できる。


HelloWorld.javaと、そのコンパイルされたクラスファイルがあるとして、
javapを 詳細表示-verbose (-v) を指定すると、

$ javap -v HelloWorld
Compiled from "HelloWorld.java"
public class jp.seraphyware.hatena20120623.HelloWorld extends java.lang.Object
  SourceFile: "HelloWorld.java"
  minor version: 0
  major version: 50
  Constant pool:
...(以下省略)...

クラスファイルの情報が出力される。


その上のあたりに、

  • minor version
  • major version

とあるのが、このクラスファイルがターゲットとしているJavaVMを示している。


このクラスファイルのバージョンと、JavaSEの対応関係は、以下のようになっている。*1

(以下は、メジャーバージョンを整数部、マイナーバージョンを少数部として表現している。)

JavaSEのバージョン クラスファイルのバージョン リリース年
1.0.2 45.3 1996
1.1 45.3 1997
J2SE1.2 46.0 1998
J2SE1.3 47.0 2000
J2SE1.4 48.0 2002
J2SE5 49.0 2004
JavaSE6 50.0 2006
JavaSE7 51.0 2011
Java8 52.0 2014 2019/1/11追記
Java9 53.0 2017 2019/1/11追記
Java10 54.0 2018 2019/1/11追記
Java11 55.0 2018 2019/1/11追記

↓↓↓ ここが現在も詳しい ↓↓↓ (2019/1/11追記)

www.ne.jp


結局、この情報は先人に調べていただいたものそのものなのだが、
自分で調べるには以下のようにすれば良いようである。(Mac OS Xの場合の例)

$ for v in 1.2 1.3 1.4 1.5 1.6;do javac -J-Dfile.encoding=UTF-8 -source 1.2 -target $v *.java;echo $v;javap -v HelloWorld | grep 'version'; done
1.2
  minor version: 0
  major version: 46
1.3
  minor version: 0
  major version: 47
1.4
  minor version: 0
  major version: 48
1.5
  minor version: 0
  major version: 49
1.6
  minor version: 0
  major version: 50

※ あらかじめHelloWorld.javaファイルを用意しておき、どのバージョンでもコンパイルできるように1.2準拠にしておく。
※ -J-Dfile.encoding=UTF-8Mac OS Xでjavacを使う場合、現在のLANG環境変数がja_JP.UTF-8にかかわらず固定的にSJISで出力してくるため、明示的にUTF-8であることを伝えるものである.
※ 2012/6現在のMacで試したのでJavaSE7は存在していないが、Windowsで確認したところではJDK7でのコンパイルしたクラスファイルのバージョンは「51.0」であった。

結論

保守等で久しく触れるソースの場合、以前のバージョンが何であったのかを知るのは、とても重要なことと思う。

しかし、Javaソースコード上には、明確にターゲットのバージョンを記述するところはなく、
ビルドスクリプトやantのようなものがあったとしても、必ずしも明示的にバージョンが指定してあるとはかぎらない。(環境のデフォルトを採用する、というのが一般的のようにも思う。)


そうゆうときに、javapでターゲットのバージョンを把握できることは重要な情報になると思われる。

*1:OracleJava Virtual Machine Specification - Chapter 4. The class File Formatを探してみたが、部分的な情報しかなく、はっきりとした対応関係が記載されたものは見つけられなかった。"Table 4.21. Predefined class file attributes"に、それに近いものはあったが、そのものの情報ではない。