はい、バイトコードもタイプセーフです。まず、ダウンキャストするたびに使用されるバイトコード命令があります。checkcast
Object obj = "abc";
String s = (String)obj;
は次のように翻訳されます。
aload_1
checkcast #3 // class java/lang/String
astore_2
次にinvokevirtual
、特定の型のオブジェクトを期待するものもあります。間違った型を渡すと、JVM はそのようなクラスのロードを拒否します。Java 言語では実現できないと思うので、少しハッキングしました。次のコード:
Integer x = 1;
String s = "abc";
int len = s.length();
は次のように翻訳されます。
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: ldc #3 // String abc
7: astore_2
8: aload_2
9: invokevirtual #4 // Method java/lang/String.length:()I
12: istore_3
ローカル変数8
をロードする命令に注意してください。s
に置き換えた16進エディタを使用aload_2
して、オブジェクト(ローカル変数)aload_1
を呼び出そうとしました:String.length()
Integer
x
$ java Test
Exception in thread "main" java.lang.VerifyError:
Bad type on operand stack in method Test.main([Ljava/lang/String;)V at offset 9
興味があれば、クラス検証を無効にすると、地獄が解き放たれます。
$ java -Xverify:none Test
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.length(String.java:623)
at Test.main(Test.java:6)
もっと悪いかもしれません。
最後になりましたが、特定のプリミティブ (float、double、int など) 専用のオペコードがたくさんあります。