コンパイルされたクラスファイルのターゲットとしていた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追記)
結局、この情報は先人に調べていただいたものそのものなのだが、
自分で調べるには以下のようにすれば良いようである。(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-8 はMac OS Xでjavacを使う場合、現在のLANG環境変数がja_JP.UTF-8にかかわらず固定的にSJISで出力してくるため、明示的にUTF-8であることを伝えるものである.
※ 2012/6現在のMacで試したのでJavaSE7は存在していないが、Windowsで確認したところではJDK7でのコンパイルしたクラスファイルのバージョンは「51.0」であった。
結論
保守等で久しく触れるソースの場合、以前のバージョンが何であったのかを知るのは、とても重要なことと思う。
しかし、Javaのソースコード上には、明確にターゲットのバージョンを記述するところはなく、
ビルドスクリプトやantのようなものがあったとしても、必ずしも明示的にバージョンが指定してあるとはかぎらない。(環境のデフォルトを採用する、というのが一般的のようにも思う。)
そうゆうときに、javapでターゲットのバージョンを把握できることは重要な情報になると思われる。
参考文献(転載元)
http://0xc000013a.blog96.fc2.com/blog-entry-15.html
http://www.rgagnon.com/javadetails/java-0544.html
*1:OracleのJava Virtual Machine Specification - Chapter 4. The class File Formatを探してみたが、部分的な情報しかなく、はっきりとした対応関係が記載されたものは見つけられなかった。"Table 4.21. Predefined class file attributes"に、それに近いものはあったが、そのものの情報ではない。