जावा जेनेरिक का उपयोग करते हुए अलग-थलग मान


81

मैं जेनरिक का उपयोग करते समय एक एनम के मूल्यों के माध्यम से पुनरावृति का रास्ता खोजने की कोशिश कर रहा हूं। यह सुनिश्चित करने के लिए नहीं कि यह कैसे करना है या यदि यह संभव है।

निम्न कोड दिखाता है कि मैं क्या करना चाहता हूं। ध्यान दें कि निम्नलिखित कोड में T.values ​​() मान्य नहीं है।

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : T.values()) {  // INVALID CODE
            availableOptions.add(option);
        }
    }
}

यहां बताया गया है कि मैं एक फ़िल्टर ऑब्जेक्ट को कैसे इंस्टेंट करूंगा:

Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);

इस प्रकार परिभाषित किया गया है:

public enum TimePeriod {
    ALL("All"), 
    FUTURE("Future"), 
    NEXT7DAYS("Next 7 Days"), 
    NEXT14DAYS("Next 14 Days"), 
    NEXT30DAYS("Next 30 Days"), 
    PAST("Past"),
    LAST7DAYS("Last 7 Days"), 
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days"); 

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

मुझे लगता है कि किसी सूची में एनम के मूल्यों को कॉपी करने का कोई मतलब नहीं हो सकता है, लेकिन मैं एक पुस्तकालय का उपयोग कर रहा हूं जिसे इनपुट के रूप में मूल्यों की एक सूची की आवश्यकता है और यह एनम के साथ काम नहीं करेगा।


EDIT 2/5/2010:

प्रस्तावित अधिकांश उत्तर बहुत समान हैं और ऐसा कुछ करने का सुझाव देते हैं:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        Class<T> clazz = (Class<T>) selectedOption.getClass();
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

यह बहुत अच्छा काम करेगा अगर मैं यह सुनिश्चित कर सकूँ कि चयनित ऑप्शन का गैर-शून्य मान है। दुर्भाग्य से, मेरे उपयोग के मामले में, यह मान अक्सर शून्य है, क्योंकि सार्वजनिक फ़िल्टर () नो-आर्ग कंस्ट्रक्टर भी है। इसका मतलब है कि मैं NPE प्राप्त किए बिना एक चयनितOget.getClass () नहीं कर सकता। यह फ़िल्टर वर्ग उपलब्ध विकल्पों की एक सूची का प्रबंधन करता है जो विकल्पों में से चुना गया है। जब कुछ भी नहीं चुना जाता है, तो चयनित किया जाना अशक्त है।

केवल एक चीज जो मैं इसे हल करने के लिए सोच सकता हूं, वह वास्तव में निर्माणकर्ता में एक कक्षा में पास करना है। तो कुछ इस तरह:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(Class<T> clazz) {
        this(clazz,null);
    }

    public Filter(Class<T> clazz, T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

किसी भी विचार कैसे निर्माण में एक अतिरिक्त कक्षा पैरामीटर की आवश्यकता के बिना ऐसा करने के लिए?


1
getClassयदि enum लगातार एक गुमनाम उपवर्ग (है कोड भी असफल हो जायेगी उदाहरण )। getDeclaringClassइसके बजाय उपयोग किया जाना चाहिए।
रेडियोडफ़

जवाबों:


125

यह वास्तव में एक कठिन समस्या है। आपको जिन चीजों को करने की ज़रूरत है उनमें से एक है जावा को बताएं कि आप एक एनम का उपयोग कर रहे हैं। यह बताते हुए कि आप अपने जेनेरिक के लिए एनम वर्ग का विस्तार करते हैं। हालाँकि इस वर्ग में मान () फ़ंक्शन नहीं है। तो आपको वह वर्ग लेना होगा जिसके लिए आप मान प्राप्त कर सकते हैं।

निम्नलिखित उदाहरण से आपको अपनी समस्या को ठीक करने में मदद करनी चाहिए:

public <T extends Enum<T>> void enumValues(Class<T> enumType) {
        for (T c : enumType.getEnumConstants()) {
             System.out.println(c.name());
        }
}

क्या c.name () एनम आइटम का नाम नहीं है? इसके मूल्य को वापस करने के बारे में कैसे? कहो, एक क्विज़ ("क्विज़ी") आइटम के लिए, "क्विज़ी" लौटा देना और क्विज़ नहीं।
स्टीफन

आप enum कि मूल्य कहते हैं रिटर्न पर एक विधि की आवश्यकता है कि के लिए: getFriendlyName()। फिर आपको अपने एनम में एक इंटरफ़ेस जोड़ना होगा और फिर एनम और इंटरफ़ेस दोनों प्रकार की आवश्यकता के लिए ऊपर के जेनेरिक को अनुकूलित करना होगा T। तब यह कार्य कुछ इस तरह हो जाता है:public <E extends Enum<?> & EnumWithFriendlyName> void friendlyEnumValues(Class<T> enumType)
थिरलर

17

एक अन्य विकल्प EnumSet का उपयोग करना है:

class PrintEnumConsants {

    static <E extends Enum <E>> void foo(Class<E> elemType) {
        for (E e : java.util.EnumSet.allOf(elemType)) {
            System.out.println(e);
        }
    }

    enum Color{RED,YELLOW,BLUE};
    public static void main(String[] args) {
        foo(Color.class);
    } 

}

6

पूर्णता के लिए, JDK8 हमें एनम वर्ग में सिंथेटिक का उपयोग करने की आवश्यकता के बिना इसे प्राप्त करने का अपेक्षाकृत साफ और अधिक संक्षिप्त तरीका देता है values():

एक सरल एनम दिया गया है:

private enum TestEnum {
    A,
    B,
    C
}

और एक परीक्षण ग्राहक:

@Test
public void testAllValues() {
    System.out.println(collectAllEnumValues(TestEnum.class));
}

यह प्रिंट करेगा {A, B, C}:

public static <T extends Enum<T>> String collectAllEnumValues(Class<T> clazz) {
    return EnumSet.allOf(clazz).stream()
            .map(Enum::name)
            .collect(Collectors.joining(", " , "\"{", "}\""));
}

कोड को विभिन्न तत्वों को पुनः प्राप्त करने या एक अलग तरीके से इकट्ठा करने के लिए तुच्छ रूप से अनुकूलित किया जा सकता है।


5

असुरक्षित कास्ट का उपयोग करना:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        Class<T> clazz = (Class<T>) selectedOption.getClass();
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

getClassविफल रहेगा यदि एनम स्थिरांक एक अनाम उपवर्ग ( उदाहरण ) है। getDeclaringClassइसके बजाय उपयोग किया जाना चाहिए।
रेडियोडफ

1

यदि आप सुनिश्चित हैं कि selectedOptionकंस्ट्रक्टर Filter(T selectedOption)अशक्त नहीं है। आप प्रतिबिंब का उपयोग कर सकते हैं। इस प्रकार सं।

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : this.selectedOption.getClass().getEnumConstants()) {  // INVALID CODE
            availableOptions.add(option);
        }
    }
}

उम्मीद है की यह मदद करेगा।


1

सामान्य गणना का मूल्य पाने के लिए :

  protected Set<String> enum2set(Class<? extends Enum<?>> e) {
    Enum<?>[] enums = e.getEnumConstants();
    String[] names = new String[enums.length];
    for (int i = 0; i < enums.length; i++) {
      names[i] = enums[i].toString();
    }
    return new HashSet<String>(Arrays.asList(names));
  }

उपरोक्त विधि में नोट करें .String () विधि पर कॉल करें।

और फिर इस तरह के एक toString () विधि के साथ गणना को परिभाषित करें।

public enum MyNameEnum {

  MR("John"), MRS("Anna");

  private String name;

  private MyNameEnum(String name) {
    this.name = name;
  }

  public String toString() {
    return this.name;
  }

}

0

जड़ समस्या यह है कि आपको किसी सरणी को सूची में बदलने की आवश्यकता है, है ना? आप इसे एक विशिष्ट प्रकार (T के बजाय TimePeriod) और निम्न कोड का उपयोग करके कर सकते हैं।

तो कुछ इस तरह का उपयोग करें:

List<TimePeriod> list = new ArrayList<TimePeriod>();
list.addAll(Arrays.asList(sizes));

अब आप सूची को किसी भी विधि से पारित कर सकते हैं जो सूची चाहता है।


0

यदि आप फ़िल्टर की घोषणा करते हैं

public class Filter<T extends Iterable>

फिर

import java.util.Iterator;

public enum TimePeriod implements Iterable {
    ALL("All"),
    FUTURE("Future"),
    NEXT7DAYS("Next 7 Days"),
    NEXT14DAYS("Next 14 Days"),
    NEXT30DAYS("Next 30 Days"),
    PAST("Past"),
    LAST7DAYS("Last 7 Days"),
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days");

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    public Iterator<TimePeriod> iterator() {
        return new Iterator<TimePeriod>() {

            private int index;

            @Override
            public boolean hasNext() {
                return index < LAST30DAYS.ordinal();
            }

            @Override
            public TimePeriod next() {
                switch(index++) {
                    case    0   : return        ALL;
                    case    1   : return        FUTURE;
                    case    2   : return        NEXT7DAYS;
                    case    3   : return        NEXT14DAYS;
                    case    4   : return        NEXT30DAYS;
                    case    5   : return        PAST;
                    case    6   : return        LAST7DAYS;
                    case    7   : return        LAST14DAYS;
                    case    8   : return        LAST30DAYS;
                    default: throw new IllegalStateException();
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

और उपयोग काफी आसान है:

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        Iterator<TimePeriod> it = selectedOption.iterator();
        while(it.hasNext()) {
            availableOptions.add(it.next());
        }
    }
}

दिलचस्प दृष्टिकोण। मुझे लगता है कि यह बिना कक्षा <T> घोषित किए बिना काम करेगा। हालाँकि, मैं अपने सभी एनम को नहीं बदलना चाहूंगा, इसलिए मैं एक अलग तरीके की ओर झुक रहा हूं।
वृषभ

0

एक Enum के आसपास एक आवरण वर्ग के उदाहरण के नीचे। थोड़ा अजीब बू है जो मुझे चाहिए:

public class W2UIEnum<T extends Enum<T> & Resumable> {

public String id;
public String caption;

public W2UIEnum(ApplicationContext appContext, T t) {
    this.id = t.getResume();
    this.caption = I18N.singleInstance.getI18nString(t.name(), "enum_"
            + t.getClass().getSimpleName().substring(0, 1).toLowerCase()
            + t.getClass().getSimpleName().substring(1,
                    t.getClass().getSimpleName().length()), appContext
            .getLocale());
}

public static <T extends Enum<T> & Resumable> List<W2UIEnum<T>> values(
        ApplicationContext appContext, Class<T> enumType) {
    List<W2UIEnum<T>> statusList = new ArrayList<W2UIEnum<T>>();
    for (T status : enumType.getEnumConstants()) {
        statusList.add(new W2UIEnum(appContext, status));
    }
    return statusList;
}

}


0

मैंने इसे इस तरह किया

    protected List<String> enumToList(Class<? extends Enum<?>> e) {
            Enum<?>[] enums = e.getEnumConstants();
            return Arrays.asList(enums).stream()
                   .map(name -> name.toString())
                   .collect(Collectors.toList());
        }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.