javapでバイトコードを調べる
javap -cでクラスファイルを逆コンパイルし、Javaの構文がバイトコードにどう変換されるかを理解します。
「javapでバイトコードを調べる」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
バイトコードを調べる理由
バイトコードを理解すると、JVM が Java コードを実際にどのように実行するかが分かります。パフォーマンス問題のデバッグ、コンパイラーの最適化の理解、合成コード(ラムダや内部クラス)が想定どおりに動作することの確認に役立ちます。
javapの基本的な使い方
javap ClassName は、クラスの公開 API(メソッドシグネチャ、フィールド宣言)を表示します。現在のディレクトリまたはクラスパスから .class ファイルを読み込みます。
# Compile first:
javac User.java
# Display public API:
javap User
# Output:
# public class User {
# public java.lang.String getName();
# public int getAge();
# }-cでバイトコードを逆アセンブル
javap -c User は、各メソッドの JVM 命令セット(オペコード)を表示します。実行フローを理解するための中心的なビューです。
# javap -c User
# public java.lang.String getName();
# Code:
# 0: aload_0
# 1: getfield #2 // Field name:Ljava/lang/String;
# 4: areturn-vによる詳細出力
javap -v User は、定数プール、アクセスフラグ、スタックサイズ、例外テーブルを追加で表示します。詳細な分析や ClassCastException のデバッグに不可欠です。
# javap -v User
# Constant pool:
# #1 = Methodref #5.#22 // java/lang/Object."<init>":()V
# #2 = Fieldref #4.#23 // User.name:Ljava/lang/String;
# ...よく使われるバイトコード命令
頻出するオペコードを把握しておきましょう: aload_0(this のロード)、getfield、putfield、invokevirtual、invokespecial(コンストラクター/private)、invokestatic、invokedynamic(ラムダ)、return、areturn。
ラムダとinvokedynamic
ラムダ式は invokedynamic 命令にコンパイルされます。最初の呼び出しでは LambdaMetafactory を使用してクラスを生成し、以降の呼び出しではそれを再利用します。javap -v でブートストラップメソッドのテーブルを確認できます。
// Java:
list.forEach(s -> System.out.println(s));
// Compiles to invokedynamic — javap shows:
// invokedynamic #4,0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;文字列連結の最適化
最新の javac は、"Hello " + name に対して StringBuilder ではなく invokedynamic を使用します。javap -v で StringConcatFactory のブートストラップメソッドを確認できます。
// Java 9+ string concat:
String s = "Hello " + name;
// Compiles to:
// invokedynamic #5,0 // InvokeDynamic #1:makeConcatWithConstants内部クラスへのアクセスを確認する
外部クラスが内部クラスの private フィールドにアクセスする場合(またはその逆の場合)、コンパイラーは合成された access$000 メソッドを生成します。javap -p(private メンバー)で確認できます。
# javap -p OuterClass
# static int access$000(OuterClass);
# -- synthetic bridge method generated by the compilerオートボクシングのコストを確認する
オートボクシングは、Integer.valueOf() または int.intValue() の呼び出しにコンパイルされます。javap -c を使用してボクシングが発生していることを確認し、プリミティブ型を使うべきか判断してください。
// Java:
List<Integer> list = new ArrayList<>();
list.add(42); // autoboxing
// Bytecode:
// bipush 42
// invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;バイトコードからtry-catchを読み取る
例外ハンドラーは例外テーブルのエントリとして現れ、javap -v で確認できます。各エントリには try の開始位置、終了位置、ハンドラー、捕捉する型が示されます。
# Exception table:
# from to target type
# 2 10 15 Class java/io/IOException
# -- means: if IOException in bytes 2-10, jump to handler at byte 15クラスファイルヘッダー
クラスファイルヘッダーには、マジックナンバー(CAFEBABE)、メジャー/マイナーバージョン、アクセスフラグが含まれます。javap -v でメジャーバージョンを確認できます。この値から、そのクラスをコンパイルした Java リリースが分かります。
# javap -v User
# minor version: 0
# major version: 61 <- Java 17
# flags: ACC_PUBLIC, ACC_SUPER確認問題
各メソッドの JVM オペコードを表示する javap のフラグはどれですか?
まとめ
オペコードには javap -c を、詳細情報全体には javap -v を使用します。主要なオペコードとして、invokevirtual、invokespecial、invokedynamic、getfield を把握しておきましょう。ラムダ、ボクシング、文字列連結を調べると、コンパイラーの出力を理解できます。
よくある質問
「javapでバイトコードを調べる」レッスンは無料ですか?
はい。「javapでバイトコードを調べる」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「javapでバイトコードを調べる」で何を学びますか?
javap -cでクラスファイルを逆コンパイルし、Javaの構文がバイトコードにどう変換されるかを理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「javapでバイトコードを調べる」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- クラスロードの段階:ロード、リンク、初期化
- ClassLoader の階層とカスタムローダー
- javapでバイトコードを調べる
- JITコンパイルと階層型コンパイル