2014-11-02 18 views
14

Di seguito è il primo generici Java che io abbia mai scritto:No ClassCastException è gettato all'interno generici Java

public class MyClass { 

    public static <T> T castToAnotherType(Object param) { 
     T ret = null; 
     try { 
      ret = (T) param; 
     } catch (ClassCastException e) { 
      System.out.print("Exception inside castToAnotherType()"); 
     } 
     return ret; 
    } 

    public static void main(String[] args) { 
     try { 
      String obj = MyClass.castToAnotherType(new Object()); 
     } catch (ClassCastException e) { 
      System.out.print("Exception outside castToAnotherType()"); 
     } 
    } 

} 

Il risultato è "Eccezione di fuori castToAnotherType()". Perché l'eccezione non si è verificata all'interno del metodo generico?

risposta

15

T è effettivamente cancellato durante la compilazione. Vedi here:

Generics sono state introdotte per il linguaggio Java per fornire il tipo più stretta controlli in fase di compilazione e per supportare la programmazione generica. Per attuare farmaci generici, il compilatore Java si applica la cancellazione di tipo a:

  • sostituire tutti i parametri di tipo in tipi generici con i loro limiti o oggetto se i parametri di tipo sono illimitati. Pertanto, il codice prodotto, , contiene solo classi, interfacce e metodi ordinari.
  • Inserire tipi di cast, se necessario, per preservare la sicurezza del tipo. Generare metodi di bridge per preservare il polimorfismo in tipi generici estesi.
  • La cancellazione del tipo garantisce che non vengano create nuove classi per i tipi parametrizzati ; di conseguenza, i generici non comportano nessun sovraccarico di runtime.

Così il vostro castToAnotherType ottiene T cancellati in ca. il seguente:

public static Object castToAnotherType(Object param) { 
    Object ret = null; 
    try { 
     ret = (Object) param; 
    } catch (ClassCastException e) { 
     System.out.print("Exception inside castToAnotherType()"); 
    } 
    return ret; 
} 

Che ovviamente non produce alcun ClassCastException.

main(...) è una storia diversa, risulta nella seguente:

public static void main(String[] args) { 
    try { 
     String obj = (String) MyClass.castToAnotherType(new Object()); 
    } catch (ClassCastException e) { 
     System.out.print("Exception outside castToAnotherType()"); 
    } 
} 

che produce il ClassCastException quando si cerca di lanciare Object-String.

Vedere la parte Type Erasure dello Generics tutorial.

+0

è molto più complicata di quanto pensassi. Ho bisogno di passare più tempo a studiare per capire pienamente questo quando ho tempo. Per ora, hai qualche suggerimento su come risolverlo? Ad esempio: return 'null' quando' param' non può essere lanciato per digitare 'T'? – Livy

+1

@Livy Questa è un'altra domanda, si prega di chiedere separatamente. In breve, uno dei metodi sarebbe passare il 'Class targetClass' come parametro extra. Ma mi piacerebbe vedere altre risposte. :) – lexicore

4

Ebbene, dal momento che il compilatore cancella i parametri di tipo generico, la fusione all'interno del metodo è sostanzialmente equivalente a:

Object ret = null; 
    try { 
     ret = (Object) param; 
    } 
    ... 

che non è un problema, indipendentemente da ciò che si passa al metodo (dal momento che qualsiasi oggetto può essere lanciato su Object).

Tuttavia, quando si tenta di assegnare tale oggetto a una stringa, nel metodo principale, si verifica ClassCastException, dal momento che Object non può essere trasmesso a String.

3

Tutti i tipi generici vengono cancellati nel codice compilato. Per quanto riguarda il codice compilato, castToAnotherType restituisce appena un Object. Tuttavia, il tuo metodo main tenta di assegnarlo a un String e non è un String, in modo da produrre uno ClassCastException.

http://en.wikipedia.org/wiki/Type_erasure

3

Questo perché di cancellazione di tipo generico,

 T ret = null; 
     try { 
      ret = (T) param; 
... 

è tradotto da compilatore in

 Object ret = null; 
     try { 
      ret = (T) param; 
... 
+1

In realtà 'ret = (Object) param;'. – immibis