2009-08-11 8 views
17

मेरे पास कुछ हद तक सहायक तरीके हैं जो एनम मानों को एचटीएमएल <select> तत्व द्वारा प्रदर्शित करने के लिए उपयुक्त तारों की सूची में परिवर्तित करते हैं। मैं सोच रहा था कि क्या इन्हें एकल पॉलिमॉर्फिक विधि में दोबारा करना संभव है।पॉलिमॉर्फिक रूप से जावा एनम मानों को स्ट्रिंग्स की सूची में परिवर्तित करें

यह मेरा मौजूदा तरीकों में से एक का एक उदाहरण है:

/** 
* Gets the list of available colours. 
* 
* @return the list of available colours 
*/ 
public static List<String> getColours() { 
    List<String> colours = new ArrayList<String>(); 

    for (Colour colour : Colour.values()) { 
    colours.add(colour.getDisplayValue()); 
    } 

    return colours; 
} 

मैं अभी भी बहुत जावा जेनरिक के लिए नया हूँ, इसलिए मुझे यकीन है कि कैसे विधि करने के लिए एक सामान्य enum पारित करने के लिए नहीं कर रहा हूँ और उस राशि लूप के लिए भी इस्तेमाल किया जाता है।

ध्यान दें कि मुझे पता है कि प्रश्नों की संख्या में getDisplayValue विधि होगी, लेकिन दुर्भाग्य से वे एक सामान्य प्रकार साझा नहीं करते हैं जो इसे परिभाषित करता है (और मैं इसे पेश नहीं कर सकता), तो मुझे लगता है कि उसे करना होगा प्रतिबिंबित किया जा सकता है ...?

किसी भी मदद के लिए अग्रिम धन्यवाद।

उत्तर

17

Class#getEnumConstants() का उपयोग कर सरल है:

static <T extends Enum<T>> List<String> toStringList(Class<T> clz) { 
    try { 
     List<String> res = new LinkedList<String>(); 
     Method getDisplayValue = clz.getMethod("getDisplayValue"); 

     for (Object e : clz.getEnumConstants()) { 
      res.add((String) getDisplayValue.invoke(e)); 

     } 

     return res; 
    } catch (Exception ex) { 
     throw new RuntimeException(ex); 
    } 
} 

यह पूरी तरह से टाइपएफ़ नहीं है क्योंकि आप getDisplayValue विधि के बिना एनम प्राप्त कर सकते हैं। कहीं एक उपयोगिता वर्ग में

सबसे पहले एक सहायक विधि और स्थिर भीतरी वर्ग:

@SuppressWarnings("unchecked") 
    public static <T> T generateProxy(Object realObject, Class<?>... interfaces) { 
     return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject)); 
    } 


    private static class SimpleInvocationHandler implements InvocationHandler { 
     private Object invokee; 

     public SimpleInvocationHandler(Object invokee) { 
      this.invokee = invokee; 
     } 

     public Object invoke(Object proxy, Method method, Object[] args) 
       throws Throwable { 
      method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes()); 
      if (!method.isAccessible()) { 
       method.setAccessible(true); 
      } 
      try { 
       return method.invoke(invokee, args); 
      } catch (InvocationTargetException e) { 
       throw e.getTargetException(); 
      } 
     } 
    } 

और फिर अपने enum के साथ कि एक साथ रखा:

+0

getDisplayValue विधि का उपयोग नहीं करता है। –

+0

संशोधित, कृपया अपवाद हैंडलिंग की समीक्षा करें – dfa

+0

अच्छी तरह से काम करता है, धन्यवाद! –

-1

(क्षमा करें, इस सी # है। मैं नहीं देखा था कि प्रश्न जावा के लिए किया गया था।)

public string[] GetValues<T>() 
{ 
    return Enum.GetNames(typeof(T)); 
} 

जावा के लिए, निश्चित रूप से, सभी enum प्रकार अभी भी java.util.Enum से विरासत है, तो आप लिख सकते हैं:

public string[] getValues<T extends Enum<T>>() 
{ 
    // use reflection on T.class 
} 

java.util.Enum के बाद से वास्तव में मूल्यों(), मुझे लगता है कि प्रतिबिंब जाना एक ही रास्ता है को लागू नहीं करता है।

+0

आपका जावा कोड संकलित भी नहीं करता है; FYI Enum.GetNames (Typeof (T)) – dfa

3

यहां दो चीज़ें हैं जो आप यहां कर सकते हैं।

public interface DisplayableSelection { 
    public String getDisplayValue(); 
} 

private static List<String> getStrings (Collection<DisplayableSelection> things) { 
    List<String> retval = new ArrayList<String>(); 
    for (DisplayableSelection thing : things) { 
    retval.add(thing.getDisplayValue()); 
    } 
} 

private static List<String> getColours() { 
    return getStrings(Colour.values()); 
} 

तुम सच में उस प्रकार आंतरिक रूप से ध्यान देते हैं: पहला (सरल, और इसलिए बेहतर) जिस तरह से सिर्फ अपने getStrings() विधि कुछ इंटरफेस की एक सूची ले, और अपने enums कि इंटरफ़ेस को लागू करना है करने के लिए किया जाएगा एक एनम है, आप इस तथ्य का भी उपयोग कर सकते हैं कि सभी समेकित प्रकार स्वचालित रूप से अंतर्निहित प्रकार Enum subclass। तो, आपके (उदाहरण के लिए अस्वीकरण: मुझे लगता है कि इस संकलित है, लेकिन वास्तव में यह प्रयास नहीं किया है):

public interface DisplayableEnum { 
    public String getDisplayValue(); 
} 

private static <T extends Enum<T> & DisplayableEnum > List<String> getDisplayValues(Class<T> pClass) { 
    List<String> retval = new ArrayList<String>(); 
    for (DisplayableSelection thing : pClass.getEnumConstants()) { 
    retval.add(thing.getDisplayValue()); 
    } 
} 

private static List<String> getColours() { 
    return getStrings(Colour.class); 
} 

यह दूसरा रूप उपयोगी यदि आप कुछ है कि विशेष रूप से एक गणन की आवश्यकता है क्या करना चाहते हो सकता है (उदाहरण के लिए किसी कारण से EnumMap या EnumSet का उपयोग करें); अन्यथा, मैं पहले के साथ जाऊंगा (क्योंकि उस विधि के साथ, आप गैर-गणित प्रकारों का उपयोग भी कर सकते हैं, या सिर्फ गणना का सबसेट)।

+0

के स्थान पर जावा में aClass.getEnumValues ​​() का उपयोग करें, धन्यवाद, लेकिन मैंने पहले ही समझाया है कि पहला विकल्प मेरे लिए उपलब्ध नहीं है। दूसरे विकल्प के लिए –

+0

+1 क्योंकि यह सुनिश्चित करने के द्वारा स्वीकार किए गए उत्तर प्रकार को सुरक्षित करता है यह सुनिश्चित करता है कि यह getDisplayValue() को लागू करता है। और प्रतिबिंब हटा देता है। दूसरे विकल्प के लिए –

+0

+1, कोई प्रतिबिंब नहीं, @Sbodd you rock ;-) स्काला एनम, त्रुटि कार्यान्वयन के कारण जावा में काम करने की कोशिश कर रहा है। – virtualeyes

0

नोट मुझे पता है कि प्रश्न में enums सब होगा कि getDisplayValue विधि है, लेकिन दुर्भाग्य से वे एक आम प्रकार में उसके द्वारा निर्धारित हिस्सा नहीं है (और मैं एक परिचय नहीं कर सकते हैं), तो मुझे लगता है कि को पर प्रतिबिंबित करना होगा ...?

आप सही ढंग से अनुमान लगा रहे हैं। एक विकल्प होगा कि प्रदर्शन मूल्य लौटकर सभी लागू toString() लागू करें - लेकिन यदि आप उन्हें इंटरफ़ेस लागू नहीं कर सकते हैं तो मुझे लगता है कि यह संभव नहीं है।

+0

दुर्भाग्य से मैं ऐसा नहीं कर सकता, क्योंकि ToString के आउटपुट को डेटाबेस में मानों से मेल खाना पड़ेगा जो मैं नहीं बदल सकता! –

10

आप कुछ उपयोगिता कक्षा में इस विधि छड़ी कर सकते हैं:

public static <T extends Enum<T>> List<String> getDisplayValues(Class<T> enumClass) { 
    try { 
     T[] items = enumClass.getEnumConstants(); 
     Method accessor = enumClass.getMethod("getDisplayValue"); 

     ArrayList<String> names = new ArrayList<String>(items.length); 
     for (T item : items) 
      names.add(accessor.invoke(item).toString())); 

     return names; 
    } catch (NoSuchMethodException ex) { 
     // Didn't actually implement getDisplayValue(). 
    } catch (InvocationTargetException ex) { 
     // getDisplayValue() threw an exception. 
    } 
} 

स्रोत: Examining Enums

+0

getDisplayValue विधि का उपयोग नहीं करता है। –

+0

हाँ, एहसास हुआ कि मैंने पोस्ट करने के बाद। यह अब करता है –

+0

डिस्प्लेबल कहां से आता है? –

2

मैं एक java.util.ResourceBundle एक बंडल फ़ाइल है कि toString (और शायद वर्ग के नाम) मूल्यों के नक्शे के साथ प्रयोग करेंगे तो अपने कोड अपने enums की तो हो जाता है की तरह कुछ:

bundle.getString(enum.getClass().getName() + enum.toString()); 
1

यहाँ कैसे मैं इसके बारे में जा रहा करने का सुझाव देते हैं

interface DisplayableEnum { 
     String getDisplayValue(); 
    } 

private static List<String> getFromEnum(Class<? extends Enum<?>> displayableEnum) { 
    List<String> ret = new ArrayList<String>(); 
    for (Enum e : displayableEnum.getEnumConstants()) { 
     DisplayableEnum de = generateProxy(e, DisplayableEnum.class); 
     ret.add(de.getDisplayValue()); 
    } 
    return ret; 
} 

यदि प्रदर्शन एक समस्या है तो कई प्रॉक्सी ऑब्जेक्ट्स उत्पन्न करने के लिए aroung, तो मैं एक परिवर्तनीय वर्ग बनाने के रास्ते के साथ जाऊंगा जो DisplayableEnum लागू करता है जो सी प्रत्येक enum स्थिर (एक फ्लाईवेट पैटर्न की तरह) के साथ नारंगी और वहां एक आमंत्रण हैंडलर है जो अपने वास्तविक वस्तु के बारे में अधिक लचीला है और लूप के माध्यम से प्रत्येक पास पर सही एक को आमंत्रित करता है।

3

यह दृष्टिकोण प्रतिबिंब से बचा जाता है:

public static interface Displayer<T> { 
    String displayName(T t); 
    } 

    public static <T> List<String> getDisplayNames(Iterable<? extends T> stuff, 
     Displayer<T> displayer) { 
    List<String> list = new ArrayList<String>(); 
    for (T t : stuff) { 
     list.add(displayer.displayName(t)); 
    } 
    return list; 
    } 

... लेकिन सब कुछ के लिए एक अलग प्रकार आप प्रदर्शित करना चाहते की आवश्यकता होती है:

enum Foo { 
    BAR("BAR"), BAZ("BAZ"); 
    private final String displayName; 

    private Foo(String displayName) { 
     this.displayName = displayName; 
    } 

    public String getDisplayName() { 
     return displayName; 
    } 
    } 

    public static void main(String[] args) { 
    Displayer<Foo> fooDisplayer = new Displayer<Foo>() { 
     public String displayName(Foo foo) { 
     return foo.getDisplayName(); 
     } 
    }; 

    System.out.println(getDisplayNames(Arrays.asList(Foo.BAR, Foo.BAZ), 
     fooDisplayer)); 
    } 

इस मामले में, एक गुमनाम प्रकार प्रयोग किया जाता है, लेकिन यह एक स्टेटलेस सिंगलटन या somesuch हो सकता है।

0

मैं पहली प्रतिक्रिया पर इस तरह से विधि में संपादित किया है और यह समस्या के बिना काम करते हैं और बिना किसी भी इंटरफ़ेस

public static <T extends Enum<T>> List<String> getDisplayValues(
     Class<T> enumClass) { 
    try { 
     T[] items = enumClass.getEnumConstants(); 
     Method accessor = enumClass.getMethod("toString"); 

     ArrayList<String> names = new ArrayList<String>(items.length); 
     for (T item : items) 
      names.add(accessor.invoke(item).toString()); 

     return names; 
    } catch (NoSuchMethodException ex) { 
     // Didn't actually implement getDisplayValue(). 
     Log.e(TAG, "getDisplayValues [" + ex+"]"); 
    } catch (InvocationTargetException ex) { 
     // getDisplayValue() threw an exception. 
     Log.e(TAG, "getDisplayValues [" + ex+"]"); 
    } catch (IllegalAccessException ex) { 
     // getDisplayValue() threw an exception. 
     Log.e(TAG, "getDisplayValues [" + ex+"]"); 
    } 
    return null; 
} 
-4

लोग चलो लागू .. अपनी नहीं है कि कठिन। मैं स्ट्रिंग तुलना का उपयोग कर रहा हूं .. लेकिन यदि आप चाहें तो ऑब्जेक्ट प्रकार की तुलना कर सकते हैं।

public static <T extends Enum<T>> Map<T, String> Initialize_Map(Class<T> enumClass) { 
    Map<T, String> map = new HashMap<T, String>(); 
    for (T val : enumClass.getEnumConstants()) { 
    map.put(val, val.toString() + (val.toString().equals("ENUM_ELMT") ? " (appended)" : "")); 
    } 
    return map;  
} 
संबंधित मुद्दे