2010-10-25 14 views
26

Dinamik enum aramasıyla ilgili bir derleme hatası ("Karşılıklı uyumsuzluk: ...") elde etmeye çalışıyorum.Enum.valueOf (Sınıf <T> enumType, Dize adı) soru

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

Ne yaparsam yapayım, hep bu derleme hatası ile bitirmek:

Temelde böyle bir şey başarmak istiyorum. Dürüst olmak gerekirse, jenerikler ve enumlar bana oldukça akıl almaz ...

Burada yanlış olan ne yapıyorum?

cevap

22

Bir tür değişkenine erişiminiz olmadıkça (tür veya yöntem imzasıyla) tam olarak böyle çalışmayacağını düşünüyorum.

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

bir tür değişkeni olmadan T almak için bir yolu yok: Sorun Enum.valueOf yöntemi imzadır. Bazı derleyici uyarıları bastırmak çekinmiyorsanız Ama bunu şöyle yapabiliriz:

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()); 
} 

Çıktı:

ELVIS

+0

soru çeteleler, jenerik ve yansıma ile ilgili. Eğer generic'leri görmezden gelirsek Özellikle, "Sınıf <," Enum> "gibi" nadir tür "ler için gidiyor. –

+2

Önemli olan, a) yardımcı yöntem veya tür olmadan başka türlü çalışamayacağı ve b) 'Sınıf 'ayrıca Sınıf > '(bu enum sınıflarının çalışması yoludur) türünü de tatmin eder, ancak bir tür değişkeni olmadan kontrol etmenin bir yolu yoktur. '@ SuppressWarnings', yalnızca ne yaptığınızı biliyorsanız biliyor olmanız gereken bir ek açıklamadır. –

19

sorun Class<? extends Enum<?>> beraberdir. E extends Enum<E> istiyoruz, ancak bunu elde edemiyoruz çünkü iki ayrı joker karakterimiz var.

Bu yüzden bir yöntemi çağırarak tanıtılan genel bir parametre, olası tanıtmak gerekir:

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; 
    } 
} 

Ama yansıma kirli ve çok nadiren istediğiniz şeydir. Yapma.

+1

Bu açıklama için teşekkürler, neler olup bittiğini anlamak için çok yardımcı oldu. Benim özel kullanımımda, jenerik parametre olarak bir şeyim olmadığından, seanizer'in cevabı için gideceğim. – Tom

6

Aslında alternatif bir yaklaşım var: Class.getEnumConstants'u kullanabilir ve aynı türde sorunlara sahip olmayan kendi uygulamanızı Enum.valueOf kullanabilirsiniz. Dezavantajı, bir jenerik Enum<?>'a geri dönüyorsunuz - ama hangi tipte geldiğini bilseydiniz, yine de Enum.valueOf'u kullanabilirsiniz. ziyade bir IllegalArgumentException atma daha böyle sabit olmadığını

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

(benim sürüm null döndürür unutmayın, ancak bunu değiştirmek için önemsiz bir şey.