2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【追跡検証】オブジェクト指向の申し子Javaのclassファイルをデコンパイルして。。。

Last updated at Posted at 2025-04-28

概要

過去記事で検証した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を再勉強してみようと思いました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?