Strano generics comportamento di Elenco.toArray(T[])

Mi sono imbattuto in qualcosa di molto semplice, ma estremamente sconcertante oggi. Ho bisogno di convertire un elenco di una matrice. La lista conteneva String istanze. Perfetto esempio di utilizzo di List.toArray(T[]), dato che volevo un String[] istanza. Non avrebbe funzionato, tuttavia, senza l’esplicito casting il risultato di String[].

Come uno scenario di test, ho usato il seguente codice:

import java.util.Arrays;
import java.util.List;

public class MainClass {
    public static void main(String args[]) {
        List l = Arrays.asList("a", "b", "c");
        String stuff[] = l.toArray(new String[0]);
        System.err.println(Arrays.asList(stuff));
    }
}

che non compila. È quasi una copia esatta dell’esempio nel javadoc, ma il compilatore dice il seguente:

MainClass.java:7: incompatible types
found   : java.lang.Object[]
required: java.lang.String[]
    String stuff[] = l.toArray(new String[0]);
                          ^

Se posso aggiungere un cast di String[] per compilare ED eseguire perfettamente. Ma che è non quello che mi aspettavo quando ho guardato la firma del metodo toArray:

<T> T[] toArray(T[] a)

Questo mi dice che non dovrei avere per il cast. Che cosa sta succedendo?

Edit:

Curiosamente, se modificare la lista dichiarazione:

List<?> l = Arrays.asList("a", "b", "c");

funziona anche. O List<Object>. Così non deve essere un List<String> come è stato suggerito. Sto cominciando a pensare che l’uso di materie prime List tipo di modifica anche come metodi generici all’interno, che il lavoro in classe.

Seconda modifica:

Penso di farlo ora. Quello che Tom Hawtin ha scritto in un commento qui sotto, sembra essere la migliore spiegazione. Se si utilizza un tipo generico in raw modo, tutti i generics informazioni da tale istanza verrà cancellato dal compilatore.

InformationsquelleAutor waxwing | 2009-07-02

 

5 Replies
  1. 29

    hai dimenticato di specificare il tipo di parametro per il tuo Elenco:

    List<String> l = Arrays.asList("a", "b", "c");

    in questo caso si può scrivere di sicurezza:

    String[] a = l.toArray(new String[0]);

    senza alcun cast.

    • Questo ha senso per me logicamente, ma non tecnicamente. Non guardate me, che il metodo toArray importa cosa E è associato a (cioè, la classe elemento della lista).
    • la firma di toArray è “pubblico <T> T[] toArray(T[] a)”, T è il tipo di componente della matrice passata in
    • Anche io non riesco a capire è, peggio è che funziona anche utilizzando un Elenco Oggetto<> (o Elenco<?>) ad “l”
    • La lingua specs è già piuttosto complicata, quindi, piuttosto che venire con un carico di ancora più complicate le regole parzialmente genericised codice (perché parzialmente genericise codice?), tutti i prodotti generici di farlo cadere. Credo JDK7 ha -Xlint:rawtypes che la cattura di questo errore.
    • Esattamente. T è String[] nel mio esempio. Pertanto deve restituire la Stringa[], non importa quali sono gli elementi che sono presenti nella lista.
    • Io non sono, io sono perfettamente felice con questo come una soluzione del mio problema, ora sono solo curioso di sapere. 🙂
    • il tipo effettivo di T[] è la Stringa[], per cui T è la Stringa, non T[]
    • Questo raccoglie anche: String roba[] = Array.asList(1, 2, 3).toArray(new String[0]);
    • (waxwing: Scusate, sono stato un po ‘ ambiguo. Non volevo dire “tu”, come a voi personalmente, ma, come chiunque.)
    • T viene ignorato come abbiamo scelto di ignorare i generici, attraverso la dichiarazione di l. Quindi T è come Oggetto (implicito legato).
    • È preferibile utilizzare l.toArray(new String[l.size()]); , per evitare di redundant array ridimensionamento tramite reflection.

  2. 3

    o fare

    List<?> l = Arrays.asList("a", "b", "c");  

    ancora strano

    • +1 al contatore. Non a risolvere il problema, ho notato la stessa stranezza di me.
    • peggio: si compila anche tramite Lista<Intero> ma deve bloccarsi in fase di runtime… :-/
  3. 1
    List<String> l = Arrays.asList("a", "b", "c");

    questo renderà la compilazione, si sta utilizzando i generics per dire “questa è una lista di Stringhe” in modo che il metodo toArray sa che tipo di array di ritorno.

  4. 0

    Questo perché l’elenco contiene gli oggetti, non stringhe. Aveva dichiarato elenco di List<String>, il compilatore sarebbe felice.

  5. 0

    List senza un tipo dichiarato di default “Elenco degli Oggetti”, mentre List<?> significa “Elenco degli sconosciuti”. Nel mondo di tipi generici è un dato di fatto che la “Lista di Oggetti” è diverso da “Stringa”, ma il compilatore non può dire lo stesso per la “Lista di sconosciuti”. Se hai dichiarato come sconosciute, per quanto il compilatore può dire, che è OK.

    Il punto principale è che dichiarare qualcosa come il jolly ? è diverso da dichiarazione come Oggetto. Per saperne di più sui caratteri jolly qui

Lascia un commento