バナー画像

Javaでのシステム開発経験がある方でも、Javaバイトコードと言われるとイマイチ理解出来ていない方も多いのではないでしょうか。

本記事では、読めなくても困らないけど仕組みとして理解しておきたいJavaバイトコードについてご紹介していきます。

Javaバイトコードとは


Javaバイトコードは、Java仮想マシーン(Java Virtual Machine)で実行するために生成される中間コードのことを指します。

概要

Java言語では、JVMと呼ばれる仮想マシーン上でプログラムを実行するためにJavaバイトコードと呼ばれる中間コードへ一度変換した上で、他の言語同様にコンピューターが理解するための機械語へ変換が行われます。

機械語と同じくJavaバイトコードもバイナリのため、Java言語のように人が読めるよう作成された高級言語とは異なります。

Javaでコーディングを行う際「.java」の拡張子を利用しますが、このJavaバイトコードに変換されたのが「.class」ファイルの状態です。

Javaバイトコードを読める必要はない

Javaでのプログラミングを学習する上で、Javaバイトコードを読めるようになる必要はありません。

あくまでJava言語でコーディングを行い、JVM上で実行するために変換されるのがJavaバイトコードだからです。

Javaバイトコードを直接編集する必要はなく、プログラマが実装するのは「.java」拡張子で作成するJavaバイトコードへの変換前プログラムです。

Javaのバイトコードを確認してみよう


ここからは実際にJavaのバイトコードを作成して、ファイルの中身を確認してみましょう。

Javaファイルからclassファイルを作成

サンプルでは、「Main.java」ファイルを下記の内容で作成しました。

public class Main {

	public static void main(String[] args) {
		String name = "ポテパン";

		System.out.println(name + "サンプル");
	}

}

ファイルが格納されたディレクトリで下記コマンドを実行し、コンパイルします。

javac Main.java

Javaファイルと同一階層を確認してみると「Main.class」ファイルが作成されていることが分かります。

ls
Main.class	Main.java

Javaバイトコードを開いてみよう

Javaバイトコードであるclassファイルはテキストエディタで開くことが可能です。

作成されたMain.classの一部を掲載しておきます。

java/lang/Object()Vポテパン	

java/lang/SystemoutLjava/io/PrintStream;makeConcatWithConstants&(Ljava/lang/String;)Ljava/lang/String;
java/io/PrintStreamprintln(Ljava/lang/String;)VMainCodeLineNumberTablemain([Ljava/lang/String;)V
SourceFile	Main.javaBootstrapMethods#

このように一部理解出来そうな部分もありますが、JVM実行用のJavaバイトコードとして変換されていることが分かります。

バイナリダンプで出力

次は「hexdump」コマンドでclassファイルのダンプを確認してみます。

$ hexdump -C Main.class
00000000  ca fe ba be 00 00 00 3d  00 30 0a 00 02 00 03 07  |.......=.0......|
00000010  00 04 0c 00 05 00 06 01  00 10 6a 61 76 61 2f 6c  |..........java/l|
00000020  61 6e 67 2f 4f 62 6a 65  63 74 01 00 06 3c 69 6e  |ang/Object......()V.......|
00000040  83 9d e3 83 86 e3 83 91  e3 83 b3 09 00 0a 00 0b  |................|
00000050  07 00 0c 0c 00 0d 00 0e  01 00 10 6a 61 76 61 2f  |...........java/|
省略

開発者が読み解くには難しい状態ですが、最初の「ca fe ba be」の部分がクラスファイルを識別する「マジックナンバー」、次の「00 00 00 3d」の部分が「バージョン情報」という風にコンピューターが読み取れるように意味合いが与えられています。

Javaバイトコードを逆アセンブルしてみよう


Javaバイトコードであるclassファイルは、逆アセンブルすることにより開発者にも読みやすい形式に変換することが可能です。

他の開発者が作成されたプログラムでclassファイルしか入手出来なかった場合などにも使える方法ですので試してみてください。

javapコマンド

Javaバイトコードを逆アセンブルするには「javap」コマンドを利用するのが手軽です。

様々なオプションが用意されており、Javaバイトコードの知りたい情報をピックアップして確認することが出来ます。

詳細は「javap -help」コマンドで確認してみてください。

ポテパンダの一言メモ

javapコマンド自体はOpenJDKに付属するコマンドで、ご利用のJavaによっては利用出来ない可能性もあります。

クラスファイルの詳細情報を表示

では実際に上記で作成したMain.classファイルを逆アセンブルしてみたいと思います。

javap -v Main.class  
Classfile /Users/ユーザー名/Documents/java/sample1/Main.class
  Last modified 2021/12/26; size 884 bytes
  SHA-256 checksum xxx
  Compiled from "Main.java"
public class Main
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #25                         // Main
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 3
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               
   #6 = Utf8               ()V
   #7 = String             #8             // ポテパン
   #8 = Utf8               ポテパン
   #9 = Fieldref           #10.#11        // java/lang/System.out:Ljava/io/Print

省略

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: ldc           #7                  // String ポテパン
         2: astore_1
         3: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
         6: aload_1
         7: invokedynamic #15,  0             // InvokeDynamic #0:makeConcatWith

クラスファイルのパスやチェックサム、Constant poolやCodeの内容などクラスファイルから読み取ることが出来る詳細な内容が表示されます。

Javaバイトコードの命令のみを表示

次に作成したJavaバイトコードの部分のみが知りたいんだという場合には「-c」オプションを付与することで簡単に抜き出すことが可能です。

$ javap -c Main.class
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #7                  // String ポテパン
       2: astore_1
       3: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
       6: aload_1
       7: invokedynamic #15,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
      12: invokevirtual #19                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      15: return
}

「-v」コマンドでも表示される内容ですが、Javaバイトコードの命令だけが抽出されていることが確認出来ます。

さいごに: Javaバイトコードは読めなくても問題ない!


本記事では、Javaバイトコードについて基本的な情報から実際に記述されている内容の確認方法までご紹介してきました。

Javaバイトコード自体は開発者が読める必要は全くありません。

ただし、Java言語の仕組みやクラスファイルから逆アセンブルするような場合には意味合いを理解しておく必要がありますので、今回の情報を参考にJavaバイトコードの知識を頭の片隅に残しておきましょう。

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。