3

Java バイトコードで参照変数型の概念を見た覚えがありません。型消去については少し知っていますが、この用語はジェネリックと密接に関連しているようですが、私の質問はオブジェクト参照変数全般に関するものです。Java オブジェクト参照変数の型はコンパイル後も存続しますか? それとも、変数の型は、開発者がコードが意味を成しているかどうかをコンパイラがチェックするのを助ける役割を果たしているだけなのでしょうか? 参照変数の型がコンパイルに耐えた場合、それらはバイトコードのどこに表示されますか?

編集: 皆様の貴重な貢献に感謝いたします。私が考えていたことをもう少し絞り込むために、例を追加したいと思います:

Object o = "foo";

バイトコードでは、変数 o とその型 (オブジェクト) はどこでも表現され、実行時に読み取られますか?

4

3 に答える 3

6

はい、バイトコードもタイプセーフです。まず、ダウンキャストするたびに使用されるバイトコード命令があります。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()Integerx

$ 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 など) 専用のオペコードがたくさんあります。

于 2013-02-02T20:27:39.653 に答える
2

JVM によってロードされるすべてのバイトコードは、安全であることを確認するために静的に型チェックされます。型チェックがなければ、悪意のあるバイトコードは単に int をポインタとして扱い、VM をハッキングできます。

ただし、バイトコードが型安全であるからといって、明示的な型付けがあるとは限りません。代わりに、各値には型推論によって決定される暗黙の型があります。(Java 7 以降では、各基本ブロックの先頭にすべての型を指定するメタデータを含めることも必須であり、型推論タスクがはるかに簡単になります)。

すべてが型チェックされますが、規則は Java よりも緩いことに注意してください。たとえば、バイトコードには、boolean、byte、char、または short ローカル変数などはありません。それらはすべて int にコンパイルされます。したがって、たとえば、true または false に等しくないブール値を持つことができます。また、インターフェイスはメソッドを呼び出すまでチェックされないため、インターフェイス変数は実際には任意のオブジェクトを保持できます。最後に、Hotspot VM を使用すると、byte[] と boolean[] を自由に混在させることができます。

于 2013-02-02T20:58:15.663 に答える
1

フィールドのタイプは、フィールド記述子でエンコードされます。

ローカル変数の型は、LocalVariableTable 属性(またはジェネリック型のLocalVariableFieldTypeTable 属性) にエンコードできます。また、Java 6 を対象とするクラス ファイルでは、StackMapTable 属性にエンコードする必要があります。古いクラス ファイルの場合、JVM は型推論でバイトコードの型の正確性を検証します。

したがって、フィールドと変数のタイプがバイトコードで表されていないことは正しいですが、それらはクラスファイルにあります(少なくともJava 6以降を対象とするクラスファイルの場合)。

于 2013-02-02T20:54:23.383 に答える