2015-03-31 22 views
10

Come per la documentazione Java su Erasure of Generic Types,Java Generics Inserisci Codice di cancellazione byte

Si consideri la seguente classe generica che rappresenta un nodo in una lista concatenata semplice:

public class Node<T> { 

    private T data; 
    private Node<T> next; 

    public Node(T data, Node<T> next) } 
     this.data = data; 
     this.next = next; 
    } 

    public T getData() { return data; } 
    // ... 
} 

Poiché il parametro tipo T è illimitato, il compilatore Java sostituisce con oggetto:

public class Node { 

    private Object data; 
    private Node next; 

    public Node(Object data, Node next) { 
     this.data = data; 
     this.next = next; 
    } 

    public Object getData() { return data; } 
    // ... 
} 

Ma dopo la compilazione con Java 1.7.0_11, quando l'ho aperto con qualsiasi decompilatore posso vedere lo stesso codice come il codice sorgente.

public class Node<T> 
{ 
    private T data; 
    private Node<T> next; 

    public Node(T paramT, Node<T> paramNode) 
    { 
    this.data = paramT; 
    this.next = paramNode; 
    } 

    public T getData() 
    { 
    return this.data; 
    } 
} 

Se Tipo-Erasure applicato in fase di compilazione, il codice byte non deve contenere informazioni generiche come mostrato sopra. Gentilmente, chiariscimi

NOTA: Sto usando JD-GUI come un decompilatore per analizzare il codice di byte

+0

Potrebbe riparare il link al tuo decompilatore? –

+2

C'è una differenza tra conoscere un tipo è generico e poter conoscere il tipo generico concreto. –

+1

La cancellazione cancella le informazioni di tipo generico di _oggetti_, non _types._ –

risposta

3

informazioni di tipo generico è ancora salvato nel bytecode, in particolare nelle informazioni firma dei membri della classe.

Per esempio, l'esecuzione di javap -verbose Node.class rendimenti:

... 
LocalVariableTypeTable: 
     Start Length Slot Name Signature 
      0  5  0 this Ltest/Node<TT;>; 

Guarda this section from the JVM specification:

Firme dichiarazioni codificare scritte nel linguaggio di programmazione Java che utilizzano i tipi di fuori del sistema tipo di Java Virtual Machine . Supportano il reflection e il debug, oltre alla compilazione quando sono disponibili solo i file di classe.

Un compilatore Java deve emettere una firma per qualsiasi classe, interfaccia, costruttore, metodo o campo la cui dichiarazione utilizza variabili di tipo o tipi parametrici. Specificamente, un compilatore Java deve emettere:

  • Una firma classe per qualsiasi dichiarazione di classe o interfaccia che è o generico, o ha un tipo parametrizzato come superclasse o superinterfaccia, o entrambi.

  • Una firma metodo per qualsiasi dichiarazione di metodo o il costruttore che è o generica, o ha una variabile di tipo o dei parametri, come il tipo di ritorno o di un tipo di parametro formale, o ha una variabile di tipo in una clausola throws, o qualsiasi combinazione di questi.

5

Il bytecode contiene le informazioni relative alla codice stesso, come ad esempio i tipi generici (o nomi di variabili) - non significa che sia utilizzabile dalla JVM.

Il bytecode disassemblato della classe si presenta come di seguito (si può vedere con javap -c Node.class):

public class Node<T> { 
    public Node(T, Node<T>); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: aload_1 
     6: putfield  #2     // Field data:Ljava/lang/Object; 
     9: aload_0 
     10: aload_2 
     11: putfield  #3     // Field next:LNode; 
     14: return 

    public T getData(); 
    Code: 
     0: aload_0 
     1: getfield  #2     // Field data:Ljava/lang/Object; 
     4: areturn 
} 

Si può vedere che i metodi e gli argomenti tipi generici sono lì, ma il codice stesso si riferisce all'oggetto come previsto a causa del processo di cancellazione.

3

Il fatto che la classe sia generica viene mantenuto. Per esempio, in fase di esecuzione è possibile chiamare

Node.class.getTypeParameters() 

Il prossimo pezzo di codice tornerà a "T".

Non è possibile ottenere il valore dei parametri di tipo in fase di esecuzione, ma la JVM sa che ci sono.

La cancellazione entra in gioco quando si costruisce un'istanza.

Node<Integer> node = new Node<Integer>(1, null); 
Integer i = node.getData(); 

Diventa

Node node = new Node(1, null); 
Integer i = (Integer)node.getData(); 

classi generiche sono sempre generici. Ma le istanze non contengono informazioni di tipo generico al loro interno. Il compilatore verifica che tutto ciò che hai fatto concorda con il tipo generico e quindi inserisce i cast.

0

Tutti,

spero che sia la questione decompilatore unica vale a dire JD-GUI.

Quando ho aperto con diversi decompilatore cioè JDecompiler, posso in grado di vedere il Bytecode previsto come segue:

public class Node { 

      private Object data; 
      private Node next; 

      public Node(Object obj, Node node) { 
/* 7*/  data = obj; 
/* 8*/  next = node; 
      } 

      public Object getData() { 
/* 12*/  return data; 
      } 
}