Perché non posso passare esplicitamente l'argomento type a un metodo Java generico?

StackOverflow https://stackoverflow.com/questions/24991

  •  09-06-2019
  •  | 
  •  

Domanda

Ho definito una funzione Java:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

Un modo per chiamarlo è così:

List<Integer> myList = createEmptyList(); // Compiles

Perché non posso chiamarlo passando esplicitamente l'argomento di tipo generico?:

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

Ottengo l'errore Illegal start of expression dal compilatore.

È stato utile?

Soluzione

Quando il compilatore Java non può dedurre da solo il tipo di parametro per un metodo statico, puoi sempre passarlo utilizzando il nome completo del metodo:Classe .<Tipo> metodo();

Object list = Collections.<String> emptyList();

Altri suggerimenti

Puoi, se passi il tipo come parametro del metodo.

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

I metodi non possono essere genericizzati nello stesso modo in cui lo fa un tipo, quindi l'unica opzione per un metodo con un tipo restituito generico tipizzato dinamicamente - uff, è un boccone :-) - è passare il tipo come argomento.

Per una FAQ davvero eccellente sui generici Java, vedere le domande frequenti sui generici di Angelika Langer.

.
.

Seguito:

Non avrebbe senso in questo contesto utilizzare l'argomento array come in Collection.toArray( T[] ).L'unico motivo per cui viene utilizzato un array è perché lo stesso array (pre-allocato) viene utilizzato per contenere i risultati (se l'array è abbastanza grande da contenerli tutti).Ciò consente di risparmiare sempre sull'allocazione di un nuovo array in fase di esecuzione.

Tuttavia, a fini didattici, se si desidera utilizzare la digitazione tramite array, la sintassi è molto simile:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

Era da un po' che non scavavo in quelle parti di Java, ma...

Il motivo per cui non puoi farlo è stata probabilmente una scelta progettuale degli sviluppatori del linguaggio.Tuttavia, a causa del cancellazione del tipo impiegato da Java, le informazioni sui generici vengono comunque eliminate in fase di compilazione, quindi nel tuo esempio creerebbe esattamente lo stesso codice byte indipendentemente dal fatto che tu abbia o meno il parametro type.

@Pauldoo Sì, hai ragione.È uno dei punti deboli dei generici Java, a mio avviso.

In risposta a Cheekysoft, vorrei proporre di guardare anche come viene fatto dagli stessi Java, come T[] AbstractCollection#toArray(T[]a).Penso che la versione di Cheekysoft sia superiore, ma quella Java ha il vantaggio della familiarità.

Modificare:Collegamento aggiunto.Modifica nuovamente:Ho trovato un bug su SO :)


Seguito su Cheekysoft:Bene, poiché è un elenco di qualche tipo che dovrebbe essere restituito, l'esempio corrispondente dovrebbe assomigliare a:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

Ma sì, passare l'oggetto della classe è chiaramente la soluzione migliore.Il mio unico argomento è quello della familiarità, e in questo caso esatto non vale molto (anzi è pessimo).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top