0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(String)objectの裏側:JVMバイトコードで見る型チェックの流れ

Last updated at Posted at 2025-08-24

目的

(String)object のような型変換が JVM 上でどのように処理されるかを調べる。
前段階として先ずはバイトコード上での表現を確認する。

バイトコードを生成

Test.java
public class Test {

    public static void main(String[] args){
        Object o = "hello";
        String s = (String)o;
        System.out.println(s);
    }
    
}
test@test-ThinkPad-X280:~/test/javatest$ javac Test.java 
test@test-ThinkPad-X280:~/test/javatest$ java Test 
hello
test@test-ThinkPad-X280:~/test/javatest$ javap -v Test
Classfile /home/test/test/javatest/Test.class
  Last modified 2025年8月24日; size 444 bytes
  SHA-256 checksum 075b42527f2f631c0388eaa257248062bb7489aad47541c89797f5c5f69c47ac
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #23                         // Test
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = String             #8             // hello
   #8 = Utf8               hello
   #9 = Class              #10            // java/lang/String
  #10 = Utf8               java/lang/String
  #11 = Fieldref           #12.#13        // java/lang/System.out:Ljava/io/PrintStream;
  #12 = Class              #14            // java/lang/System
  #13 = NameAndType        #15:#16        // out:Ljava/io/PrintStream;
  #14 = Utf8               java/lang/System
  #15 = Utf8               out
  #16 = Utf8               Ljava/io/PrintStream;
  #17 = Methodref          #18.#19        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #18 = Class              #20            // java/io/PrintStream
  #19 = NameAndType        #21:#22        // println:(Ljava/lang/String;)V
  #20 = Utf8               java/io/PrintStream
  #21 = Utf8               println
  #22 = Utf8               (Ljava/lang/String;)V
  #23 = Class              #24            // Test
  #24 = Utf8               Test
  #25 = Utf8               Code
  #26 = Utf8               LineNumberTable
  #27 = Utf8               main
  #28 = Utf8               ([Ljava/lang/String;)V
  #29 = Utf8               SourceFile
  #30 = Utf8               Test.java
{
  public Test();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()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=3, args_size=1
         0: ldc           #7                  // String hello
         2: astore_1
         3: aload_1
         4: checkcast     #9                  // class java/lang/String
         7: astore_2
         8: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_2
        12: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        15: return
      LineNumberTable:
        line 4: 0
        line 5: 3
        line 6: 8
        line 7: 15
}
SourceFile: "Test.java"
test@test-ThinkPad-X280:~/test/javatest$ 

キャストに関わる部分

checkcastは 実際には「型の検査だけ」を行う命令 で、参照自体は全く変わらないことが分かる。

0: ldc           #7  // 定数プールから文字列「hello」を読みこみスタックの一番上に置く
2: astore_1          // スタック上部から「hello」を取り出し変数1へ格納
3: aload_1           // 変数1の参照をスタック上部へ置く
4: checkcast #9      // スタック上部の参照を #9 (java/lang/String) にキャスト
                     // キャスト成功 → 参照はそのままスタックに残る
                     // キャスト失敗 → ClassCastException が呼ばれる
7: astore_2          // スタック上部の参照を変数2へ格納する

ここまでがバイトコードで確認できる範囲。
次回はJVMのソースコードを辿り、checkcast が内部でどのように型チェックを行っているかを理解する予定。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?