2010-10-25 12 views
26

Sto cercando di aggirare un errore di compilazione ("Abbinamento legato: ...") relativo alla ricerca dinamica di enum.Enum.valueOf (Classe <T> enumType, nome stringa) domanda

Fondamentalmente voglio ottenere qualcosa di simile:

String enumName = whatever.getEnumName(); 
Class<? extends Enum<?>> enumClass = whatever.getEnumClass(); 
Enum<?> enumValue = Enum.valueOf(enumClass, enumName); 

Qualsiasi cosa io faccia, finisco sempre con quel errore di compilazione. Onestamente, i generici e le enumerazioni sono piuttosto sconvolgenti per me ...

Cosa sto facendo di sbagliato qui?

risposta

22

Penso che non funzionerà esattamente come questo a meno che non si abbia accesso a una variabile di tipo (tramite una firma di tipo o metodo). Il problema è la firma del metodo di Enum.valueOf:

public static <T extends Enum<T>> T valueOf(
    Class<T> enumType, 
    String name 
); 

Non c'è modo di ottenere una T senza una variabile di tipo. Ma si può fare in questo modo, se si è disposti a sopprimere alcuni avvisi del compilatore:

public enum King{ 
    ELVIS 
} 

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public static void main(final String[] args){ 
    final Class<? extends Enum> enumType = King.class; 
    final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS"); 
    System.out.println(theOneAndOnly.name()); 
} 

uscita:

ELVIS

+0

La questione è di circa enumerazioni, farmaci generici e di riflessione. Se si ignora generici , qual è il punto? In particolare per "tipi rari" come 'Classe '. –

+2

Il punto è che a) non può funzionare diversamente senza un metodo di supporto o tipo eb) sappiamo per certo che qualsiasi 'Class 'soddisferà anche' Classe > '(perché è così che funzionano le classi enum) anche se non c'è modo di verificarlo senza una variabile di tipo. '@ SuppressWarnings' è un'annotazione che dovresti usare solo se sai cosa stai facendo, e lo so. –

19

Il problema è con Class<? extends Enum<?>>. Vogliamo E extends Enum<E>, ma non possiamo ottenerlo perché abbiamo due caratteri jolly distinti.

quindi abbiamo bisogno di introdurre un parametro generico, possibile introdotto chiamando un metodo:

enum MyEnum { 
    ME; 
} 

public class EnName { 
    public static void main(String[] args) { 
     Enum<?> value = of(MyEnum.class, "ME"); 
     System.err.println(value); 
    } 
    private static <E extends Enum<E>> E of(Class<E> clazz, String name) { 
     E value = Enum.valueOf(clazz, name); 
     return value; 
    } 
} 

Ma riflessione è fangoso e molto raramente ciò che si desidera. Non farlo

+1

Grazie per questa spiegazione, ha aiutato molto a capire meglio cosa sta succedendo. Dato che nel mio caso d'uso particolare non ho nulla da fornire come parametro generico, cercherò la risposta di Seanizer. – Tom

6

C'è in realtà un approccio alternativo: è possibile utilizzare Class.getEnumConstants e implementare la propria implementazione di Enum.valueOf che non presenta gli stessi problemi di tipo. Il rovescio della medaglia è che si ottiene un generico Enum<?> - ma se sapessi quale tipo avresti dovuto entrare, potresti comunque usare Enum.valueOf.

private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) { 
    return Arrays.stream(enumType.getEnumConstants()) 
       .filter(e -> e.name().equals(value)) 
       .findFirst() 
       .orElse(null); 
} 

(Si noti che la mia versione ritorna null se non esiste una costante, piuttosto che lanciare un IllegalArgumentException, ma questa è una cosa banale per cambiare.

Problemi correlati