概要
過去記事で検証したJavaの最新版の言語仕様に関する追跡検証を行いました。結果予想外な事実が判明しました。
事の起こり
以下の過去記事でオブジェクト指向の申し子Javaから有名な構文(Main classの実装)が消えた説について投稿しました。実際にはプレビュー機能として従来の実装方法、命名規則とは異なる方法で実装されたmain()関数が動作してしまうことを確認しました。さて、このclassファイル内のソースコードはどうなっているのでしょう?実は開発者に実装を求めていないだけで、コンパイル時にclassの実装などが後付けで追加されているという噂をどこかで聞いた覚えが有ります。今回はJavaのデコンパイルツール「JADX」を用いてclassファイルをデコンパイルして、吐き出されたJavaソースの中身を覗いてみようと思います。
JADXとは?
オープンソースのJava用デコンパイルツールです。所謂リバースエンジニアリングを行うためのツールです。今回JADXを用いてclassファイルをデコンパイルすることでJavaファイルを復元します。そして、そのJavaファイル内を見ることでclassファイルの元となったソースコードが見えるという寸法です。
インストール方法は上記のGitHub上のREADMEに記載されています。筆者はmacOS上にHomebrewでインストールしました。
検証に用いる資材
以下のJavaソースファイルをビルドして作成したclassファイルを用います。
$ cat NewHelloWorld.java
static void main() {
System.out.println("Hello, world!");
}
デコンパイルは簡単です。jadx <Source file name>
で実行出来ます。
$ jadx NewHelloWorld.class
INFO - loading ...
INFO - processing ...
INFO - done
クラス名のディレクトリ配下にsources/defpackage
というディレクトリが作成され、その中にNewHelloWorld.java
ファイルが格納されています。
$ tree NewHelloWorld/sources/defpackage/
NewHelloWorld/sources/defpackage/
└── NewHelloWorld.java
1 directory, 1 file
ソースファイルの中身を覗いてみる
NewHelloWorld.java
の中身を覗いてみましょう。package宣言に始まり、class宣言とコンストラクタ宣言が追記されています。しかし、予想していた結果とは少し異なりました。てっきり、Main class宣言が追加されているものだと思っていたのですが、NewHelloWorld classの宣言が追記されており、加えて、修飾子がpublic
ではなく、final
になっています。
$ cat NewHelloWorld/sources/defpackage/NewHelloWorld.java
package defpackage;
/* loaded from: NewHelloWorld.class */
final class NewHelloWorld {
NewHelloWorld() {
}
static void main() {
System.out.println("Hello, world!");
}
}
因みに、以下に示す従来のMain classの実装をコンパイルしたclassファイルをデコンパイルした結果は以下の通りです。
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
package defpackage;
/* loaded from: Main.class */
public class Main {
public static void main(String[] strArr) {
System.out.println("Hello, world!");
}
}
よく見るとmain()関数の引数がargs
からstrArr
に変わっていたり、package宣言が追加されたりしています。どうやらコンパイラは全ての情報を残している訳ではなく、コンパイル時に一部改変されている用です。
まとめ
現在Javaにプレビュー機能として実装されている新しいmain()関数の実装を採用したソースをコンパイルして作成したclassファイルをデコンパイルしてjavaソースファイルを取り出し、コンパイル時にclassがどの様に追加されている検証してみました。結果として、継承不可のfinal class
の実装が追加されていることが分かりました。前回と今回の投稿で改めてJavaを再勉強してみようと思いました。