2014-07-01 19 views
11

Nella classe generica Class<T> il metodo getConstructors() ha un tipo di ritorno con parametro di tipo generico sconosciuto anziché T. La ragione di ciò è spiegata nel javadoc.Tipo generico in getConstructors() nella classe

notare che, mentre questo metodo restituisce un array di oggetti Constructor<T> (vale a dire una serie di costruttori da questa classe), il tipo di ritorno di questo metodo è Constructor<?>[] e non Constructor<T>[] come ci si potrebbe aspettare. Questo tipo di ritorno meno informativo è necessario poiché dopo essere stato restituito da questo metodo, l'array potrebbe essere modificato per contenere oggetti Constructor per classi diverse, il che violerebbe le garanzie del tipo di Constructor<T>[].

Un mio collega e io abbiamo cercato di capire questa spiegazione. Nella nostra comprensione stanno sostanzialmente dicendo che è di tipo generico sconosciuto, perché alcuni chiamanti potrebbero mettere altri oggetti Constructor in quell'array. Abbiamo capito bene? E se è così, perché qualcuno dovrebbe progettare un'API in questo modo. Non sarebbe meglio usare il tipo specifico e fidarsi del programmatore per usare correttamente l'array? A noi sembra un po 'come "Stiamo facendo un'API peggiore perché il programmatore che lo utilizza potrebbe provare qualcosa di stupido". Dove giace il nostro errore?

+2

Buona domanda. Se questo è davvero il fondamento logico, non è così forte. Si può discutere di questo per ogni collezione di oggetti. Spetta al chiamante elaborare il risultato, non il chiamato per fornire un buon tipo di reso. –

+2

Vedere la discussione in fondo a [questa risposta] (http://stackoverflow.com/a/2914636/829571) – assylias

+0

grazie @assylias, perse quello mentre cercava una risposta.La mia domanda rimane: non è possibile usare 'Costruttore []' e affidarsi al chiamante per fare la cosa giusta? E se è così, perché deciderlo contro? –

risposta

2

Il punto menzionato da Ashu Pachauri nel commento (vale a dire che la matrice viene restituita per compatibilità con le versioni precedenti) è certamente valido. E in generale, gli array e i generici non giocano molto bene insieme. (Per la prova, cercare tutte le questioni relative alla StackOverflow "Generic Arrays" ...)

Inoltre, v'è una regola che un API dovrebbe essere facile da usare edifficile abuso. In questo caso, questo è correlato allo Principle of least astonishment: Qualcuno che ottiene i costruttori con questo metodo può eseguire una sequenza perfettamente legale di operazioni sull'array restituito e, alla fine, ricevere un ClassCastException imprevisto. Quindi si potrebbe dire che il fatto che venga restituito un array Constructor<?>[] mira a un comportamento "fail-fast".

Un esempio illustrativo:

import java.lang.reflect.Constructor; 

public class GetConstructorsReturnType 
{ 
    public static void main(String[] args) throws Exception 
    { 
     // This causes a warning, due to the cast, but imagine 
     // this was possible 
     Constructor<DerivedA> constructorsA[] = 
      (Constructor<DerivedA>[])DerivedA.class.getConstructors(); 

     // The following lines are valid due to the subtype 
     // relationship, but would not be valid if constructorsA 
     // was declared as "Constructor<?>" 
     Constructor<? extends Base> constructors[] = constructorsA; 
     constructors[0] = DerivedB.class.getConstructor(); 

     // This causes a ClassCastException (and would also not 
     // be possible constructorsA was declared as "Constructor<?>" 
     DerivedA instance = constructorsA[0].newInstance(); 
    } 
} 
class Base 
{ 
} 
class DerivedA extends Base 
{ 
    public DerivedA() 
    { 
    } 
} 
class DerivedB extends Base 
{ 
    public DerivedB() 
    { 
    } 
} 
+0

Non siamo ancora sicuri se siamo d'accordo con quel design decisione ma la tua risposta lo ha reso più comprensibile per noi. Immagino che non vada meglio di così ;-) Grazie! –

1

E 'esattamente lo stesso motivo per cui non è permesso di fare new Constructor<T>[], ma si è permesso di fare new Constructor<?>[]. Puoi applicare lo stesso argomento e dire "Non sarebbe meglio usare il tipo specifico e fidarsi del programmatore per usare correttamente l'array?" Bene, Java ha deciso di no. (Si può immaginare che all'interno del metodo getConstrucotrs, cui hanno bisogno per creare un array di Constructor, e che non possono fare new Constructor<T>[] ma possono fare new Constructor<?>[].)

Naturalmente, è possibile effettuare un cast incontrollato del Constructor<?>[] al Constructor<T>[] , ma questo ti darà un avvertimento nel tuo codice, nel qual caso ti assumerai la responsabilità di assicurarti che sia sicuro. Ma se il metodo getConstructors questo cast non controllato nel loro codice, voi come il chiamante non verrebbero mai avvisati della non-sicurezza.

Problemi correlati