2013-07-19 14 views
8

Ho notato che in Java Array.newInstance() restituisce Object, anziché T[]. È comprensibile che questo metodo sia stato introdotto prima che Java supporti tipi generici.Esistono versioni generiche di Array.newInstance?

Tuttavia è una sorpresa che non ci siano versioni generiche equivalenti di questo. Java 7's Arrays.copyOf non è lo stesso - copia il contenuto del parametro, piuttosto che creare un nuovo array fittizio (con tutti gli oggetti null all'interno).

Dal momento che l'implementazione di questo sembra banale, c'è qualche motivo per non aggiungerlo nel JRE? o non riesco a trovarne uno?

UPDATE

Sembra io fornire la mia realizzazione "banale" per fermare fraintendere della questione.

class MyArrayUtil { 
    //Generic version for classes 
    @SuppressWarnings("unchecked") 
    public static <T> T[] newArrayOf(T[] t, int len){ 
     return (T[]) Array.newInstance(t.getClass().getComponentType(), len); 
    } 
    //For array of int 
    public static int[] newArrayOf(int[] t, int len){ 
     return new int[len]; 
    } 
    //For other primitive types... 
} 

Non sto postando questo codice come risposta perché non è la risposta della domanda. La domanda è per la ragione e/o il codice esistente, non come implementare.

UPDATE

Ho aggiornato il codice per renderlo simile a Arrays.copyOf, e il vantaggio è che il programmatore può semplicemente cambiare il tipo di parametro per regolare il codice per un altro tipo. Inoltre ho eliminato l'uso di Array.newInstance per i tipi primitivi.

+0

No, è impossibile implementarlo in modalità sicura in modalità compilazione. Ad esempio, non puoi creare una nuova istanza di a: 'Lista []'. Il compilatore non saprà mai quale sia il tipo di 'T', e quindi non può garantire che il codice client sia sicuro. – Muel

+0

Dato che 'Arrays.copyOf' può fare il lavoro non ci sono ragioni ovvie per cui non si può. –

+2

'Arrays.copyOf' determina il tipo concreto dall'array da copiare. – pstanton

risposta

7

Guava fornisce just such a function. Non è la prima volta che Guava (o Apache Commons) fornisce un aiutante di uso comune che il JDK non possiede, per nessuna ragione.

Si può sapere questo, ma alcuni di sfondo per il Googler che inciampa su questo in futuro: La ragione per cui la firma non può essere fatta generica è che il metodo Array.newInstancereturned Object in Java 1.4, quindi per la compatibilità a ritroso, la versione grezza del il metodo dovrebbe anche restituire Object. Se fosse stato generified come:

<T> T[] newInstance(Class<T> componentType, int length) 

... poi il tipo di ritorno sarebbe Object[], non Object. Ciò interromperà la compatibilità, che i designer Java hanno sempre cercato di non fare.

I metodi Arrays.copyOf erano disponibili solo con Java 1.6 e quindi non dovevano preoccuparsi della compatibilità con le versioni precedenti.

+0

Ora penso di capire perché non ha molto senso avere 'newArray' supporta i tipi primitivi. Se vuoi creare un nuovo array con tipi che non sono parametri generici, puoi semplicemente usare 'new XYZ []'. Se non è il caso, devi usare il tipo di classe, e solo in questo caso la funzione 'newArray' è utile. –

+0

devi ancora passare il tipo come parametro ... – pstanton

+0

Non dovrebbe essere un problema se hai bisogno di un parametro/campo simile nella definizione della firma/classe del metodo. –

4

No, è necessario passare il tipo di calcestruzzo come parametro in un modo o nell'altro. Come hai detto, lo Arrays.copyOf mostra questo in azione.

Class<T> type = determinteTheTypeSomehow(); 
return (T[]) Array.newInstance(type, length); 
+0

'Array.newInstance' richiede una' Classe ', poiché' Arrays.copyOf' richiede 'T []', quindi richiedono un parametro aggiuntivo anziché un parametro di tipo. Mi chiedo semplicemente perché non possiamo avere un 'Arrays.newInstance' che accetta 'Classe ' o 'T []' (solo come modello, il contenuto interno viene ignorato). –

+0

sì capisco, ma stai cercando di piegare l'api alle tue esigenze che non funzioneranno mai;) Ammetto che questo può essere frustrante, tuttavia è così com'è. – pstanton

+0

Quando scrivo tipi generici, spesso passo il tipo di parametro concreto come argomento al costruttore per questo (e altri) scopi. – pstanton

3

Il motivo fondamentale per cui Array.newInstance() non può essere dichiarato come <T> T[] newInstance(Class<T> class, int size) è perché può essere utilizzato per creare matrici di primitive. Ad esempio, se passi int.class, che ha tipo Class<Integer>, allora dalla dichiarazione ti aspetteresti che restituisca un oggetto Integer[]. Tuttavia, la funzione restituisce effettivamente un oggetto int[], che non è un sottotipo di Integer[], quindi ha il tipo sbagliato.

Certo, potrebbe aggiungere un ulteriore metodo come newReferenceArrayInstance() che proibisce i tipi primitivi (ad esempio genera un'eccezione quando viene passato un tipo primitivo) e quindi può tranquillamente essere dichiarati per tornare T[]. Tuttavia, sembra come aggiungere un metodo completamente ridondante solo per evitare un cast non controllato.

Problemi correlati