type - list java generics example




Il metodo ha la stessa cancellazione di un altro metodo nel tipo (4)

Definire un singolo metodo senza tipo come void add(Set ii){}

Puoi menzionare il tipo mentre chiami il metodo in base alla tua scelta. Funzionerà per qualsiasi tipo di set.

Perché non è legale avere questi due metodi nella stessa classe?

class Test{
   void add(Set<Integer> ii){}
   void add(Set<String> ss){}
}

Ottengo l' compilation error

Il metodo add (Set) ha la stessa cancellazione aggiungere (Set) come un altro metodo nel tipo Test.

mentre posso aggirarlo, mi chiedevo perché a javac questo non piacesse.

Vedo che in molti casi la logica di questi due metodi sarebbe molto simile e potrebbe essere sostituita da un singolo

public void add(Set<?> set){}

metodo, ma questo non è sempre il caso.

Questo è un po 'più fastidioso se si vogliono avere due constructors che accettano tali argomenti perché non si può semplicemente cambiare il nome di uno dei constructors .


I generici Java utilizzano la cancellazione dei tipi. Il bit tra parentesi angolari ( <Integer> e <String> ) viene rimosso, quindi ti ritroverei con due metodi che hanno una firma identica (l' add(Set) che vedi nell'errore). Questo non è permesso perché il runtime non saprebbe quale usare per ogni caso.

Se Java ottiene sempre generici reificati, allora potresti farlo, ma probabilmente è improbabile ora.


Potrebbe essere possibile che il compilatore traduca Set (Integer) in Set (Object) nel codice byte java. Se questo è il caso, Set (Integer) verrebbe usato solo in fase di compilazione per il controllo della sintassi.


Questa regola ha lo scopo di evitare conflitti nel codice precedente che utilizza ancora tipi non elaborati.

Ecco un'illustrazione del motivo per cui non era consentito, tratto dal JLS. Supponiamo, prima che i generici venissero introdotti in Java, ho scritto un codice come questo:

class CollectionConverter {
  List toList(Collection c) {...}
}

Estendi la mia classe, in questo modo:

class Overrider extends CollectionConverter{
  List toList(Collection c) {...}
}

Dopo l'introduzione dei farmaci generici, ho deciso di aggiornare la mia biblioteca.

class CollectionConverter {
  <T> List<T> toList(Collection<T> c) {...}
}

Non sei pronto per fare aggiornamenti, quindi lasci da solo la tua classe Overrider . Per poter sovrascrivere correttamente il metodo toList() , i progettisti del linguaggio hanno deciso che un tipo non elaborato era "override-equivalent" per qualsiasi tipo generico. Ciò significa che sebbene la firma del metodo non sia più formalmente uguale alla firma della mia superclasse, il metodo continua a sovrascrivere.

Ora passa il tempo e decidi di essere pronto per aggiornare la tua classe. Ma fai un po ' toList() e invece di modificare il metodo raw toList() esistente, aggiungi un nuovo metodo come questo:

class Overrider extends CollectionConverter {
  @Override
  List toList(Collection c) {...}
  @Override
  <T> List<T> toList(Collection<T> c) {...}
}

A causa dell'override dell'equivalenza dei tipi non toList(Collection<T>) , entrambi i metodi sono in una forma valida per sovrascrivere il toList(Collection<T>) . Ma ovviamente, il compilatore deve risolvere un singolo metodo. Per eliminare questa ambiguità, le classi non possono avere più metodi che sono override-equivalenti, cioè più metodi con gli stessi tipi di parametri dopo la cancellazione.

La chiave è che questa è una regola del linguaggio progettata per mantenere la compatibilità con il vecchio codice utilizzando i tipi non elaborati. Non è una limitazione richiesta dalla cancellazione dei parametri di tipo; poiché la risoluzione del metodo si verifica in fase di compilazione, l'aggiunta di tipi generici all'identificatore del metodo sarebbe stata sufficiente.







generics