2009-06-02 97 views

答えて

29

これらは属性Signatureに格納されています。 updated Java Virtual Machine Specificationのセクション4.8.8およびフィールドタイプシグネチャのフォーマットについてはセクション4.4.4を参照してください。

はここjavap -verbose java.util.Mapを使用した例です:

public interface java.util.Map 
    SourceFile: "Map.java" 
    Signature: length = 0x2 
    00 1E 
    [other attributes omitted] 

ここSignature属性を指定します(あなたはこのようにビッグエンディアンを読めば、JVMクラスファイル形式のすべての整数の数量のようなもの)定数プール値#30( 30 = 0x1E)。そこで、見てみましょう。

const #30 = Asciz  <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/lang/Object;; 

4.4.4で指定された文法のコンテキストでこれを読んでください。したがって、これは2種類のパラメータ、K extends java.lang.ObjectV extends java.lang.Objectを使用します。型自体(Map)もクラスjava.lang.Objectを継承し、インターフェイスはありません。

14

実際にJavaジェネリックはtype erasureによって実装されているため、バイトコードには型情報はありません。例えば

は、のは、非一般的な形式で見て2 Listフィールドを宣言したクラス、ジェネリックに1つ、他を見てみましょう:

class NonGeneric { 
    List list; 
} 

そして、いずれの場合も

class Generic { 
    List<String> list; 
} 

得られたバイトコードは以下の通りです:

Code: 
    Stack=3, Locals=1, Args_size=1 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: new #2; //class java/util/ArrayList 
    8: dup 
    9: invokespecial #3; //Method java/util/ArrayList."<init>":()V 
    12: putfield #4; //Field list:Ljava/util/List; 
    15: return 

何referenはありません(ArrayListでもListでも使用されているタイプのString)に変更します。したがって、ジェネリックが実際にタイプ消去によって実装されていることがわかります。

しかし、定数プールを見ると、違いがわかります。

非ジェネリック定数プール:

Constant pool: 
const #1 = Method #6.#15; // java/lang/Object."<init>":()V 
const #2 = class #16; // java/util/ArrayList 
const #3 = Method #2.#15; // java/util/ArrayList."<init>":()V 
const #4 = Field #5.#17; // NonGeneric.list:Ljava/util/List; 
const #5 = class #18; // NonGeneric 
const #6 = class #19; // java/lang/Object 
const #7 = Asciz list; 
const #8 = Asciz Ljava/util/List;; 
const #9 = Asciz <init>; 
const #10 = Asciz ()V; 
// snip the rest // 

ジェネリック定数プール:

Constant pool: 
const #1 = Method #6.#17; // java/lang/Object."<init>":()V 
const #2 = class #18; // java/util/ArrayList 
const #3 = Method #2.#17; // java/util/ArrayList."<init>":()V 
const #4 = Field #5.#19; // Generic.list:Ljava/util/List; 
const #5 = class #20; // Generic 
const #6 = class #21; // java/lang/Object 
const #7 = Asciz list; 
const #8 = Asciz Ljava/util/List;; 
const #9 = Asciz Signature; 
const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;; 
const #11 = Asciz <init>; 
const #12 = Asciz ()V; 
// snip the rest// 

見ることができるように2つの余分な定数があり、Genericクラスでは、私たちが見ることができ、#9および#10の定数プールにあり、Listは汎用タイプStringです。

(そして、私はChris Jester-Young's answerから学んだ新しい知識を取り入れた)クラスファイルの解体でさらに探し

は、一定の#10を参照するには、右GenericクラスのCode: block前にそこにあります

java.util.List list; 
    Signature: length = 0x2 
    00 0A 

進値0Aは、定数プール#10を指し、小数で10ある:

const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;; 

したがって、フィールドが汎用タイプであることを示すために、定数プールからの情報が使用されます。

関連する問題