2009-07-23 4 views
17

अपडेट: उन सभी के लिए धन्यवाद जिन्होंने मदद की - इसका उत्तर उस में पड़ा जो मैं अपने जटिल कोड में नहीं देख रहा था और जिसे मुझे जावा 5 कॉन्वेंट रिटर्न प्रकारों के बारे में नहीं पता था ।एनमम्स के साथ जावा जेनरिक का उपयोग

मूल पोस्ट:

मैं आज सुबह कुछ के साथ प्रयोग करना रहा है। जबकि मुझे पता है कि इस पूरी समस्या से अलग तरीके से निपट सकता है, मैं खुद को यह समझने के साथ भ्रमित कर रहा हूं कि यह जिस तरह से काम कर रहा था, वह क्यों काम नहीं कर रहा है। इस पर चारों ओर पढ़ने के कुछ समय बाद, मुझे लगता है कि मैं समझने के करीब नहीं हूं, इसलिए मैं इसे एक प्रश्न के रूप में पेश करता हूं यह देखने के लिए कि क्या मैं सिर्फ बेवकूफ हूं या अगर वास्तव में कुछ है तो मुझे समझ में नहीं आता ।

मैं बहुत की तरह एक कस्टम घटना पदानुक्रम बनाया है: तो की तरह एक ठोस कार्यान्वयन के साथ

public abstract class AbstractEvent<S, T extends Enum<T>> 
{ 
    private S src; 
    private T id; 

    public AbstractEvent(S src, T id) 
    { 
     this.src = src; 
     this.id = id; 
    } 

    public S getSource() 
    { 
     return src; 
    } 

    public T getId() 
    { 
     return id; 
    } 
} 

:

public class MyEvent 
extends AbstractEvent<String, MyEvent.Type> 
{ 
    public enum Type { SELECTED, SELECTION_CLEARED }; 

    public MyEvent(String src, Type t) 
    { 
     super(src, t); 
    } 
} 

और फिर मैं की तरह तो एक ईवेंट बनाते हैं:

fireEvent(new MyEvent("MyClass.myMethod", MyEvent.Type.SELECTED)); 

जहां मेरे फायरएवेंट को परिभाषित किया गया है:

protected void fireEvent(MyEvent event) 
{ 
    for(EventListener l : getListeners()) 
    { 
     switch(event.getId()) 
     { 
      case SELECTED: 
       l.selected(event); 
       break; 
      case SELECTION_CLEARED: 
       l.unselect(event); 
       break; 
     } 
    } 
} 

तो मैंने सोचा कि यह बहुत सरल होगा लेकिन यह पता चला है कि घटना.getId() के लिए कॉल करने वाले संकलक में मुझे यह बताते हुए कि मैं Enums, केवल परिवर्तनीय int मान या enum स्थिरांक पर स्विच नहीं कर सकता।

यह MyEvent के लिए निम्न विधि जोड़ना संभव है:

public Type getId() 
{ 
    return super.getId(); 
} 

एक बार मैं ऐसा करते हैं, सब कुछ बिल्कुल काम करता है के रूप में मैं इसे करने की उम्मीद। मुझे इस के लिए एक कामकाज खोजने में दिलचस्पी नहीं है (क्योंकि मेरे पास स्पष्ट रूप से एक है), मुझे किसी भी अंतर्दृष्टि में दिलचस्पी है कि लोगों के पास ऐसा क्यों नहीं हो सकता है क्योंकि यह काम नहीं करता है क्योंकि मुझे बल्ले से बाहर निकलने की उम्मीद है।

+0

क्रिस, क्या आप 'फायरवेन्ट' युक्त कक्षा की कक्षा घोषणा दिखा सकते हैं? – notnoop

+0

समस्या वास्तव में थी कि मेरे सार तत्व जो मैंने यहां पोस्ट किया उससे कहीं अधिक जटिल है। मुझे * खिलौना कार्यान्वयन बनाया जाना चाहिए और इसे ** पोस्ट करने से पहले ** परीक्षण किया जाना चाहिए! मदद करने वाले हर किसी के लिए धन्यवाद! जवाब से यह था कि मेरी getId() विधि 'कोविरिएंट रिटर्न टाइप' थी - मेरे पास कक्षा में दफन किया गया एक और कार्यान्वयन था जिसे एनम रिटर्न प्रकार के रूप में परिभाषित किया गया था। जब मैंने इसे हटा दिया, स्विच स्टेटमेंट संकलन शुरू कर दिया। कम से कम आने के लिए –

+0

-0 ... –

उत्तर

10

यिशई सही है, और जादू वाक्यांश "covariant return types" है जो जावा 5.0 के रूप में नया है - आप एनम पर स्विच नहीं कर सकते हैं, लेकिन आप अपनी टाइप क्लास पर स्विच कर सकते हैं जो एनम को बढ़ाता है। MyEvent द्वारा विरासत में प्राप्त AbstractEvent में विधियां टाइप एरर के अधीन हैं। इसे ओवरराइड करके, आप getId() के परिणाम को अपने टाइप क्लास की ओर रीडायरेक्ट कर रहे हैं जिस तरह जावा रन-टाइम पर संभाल सकता है।

+0

यह बहुत अच्छा है - मैंने पॉइंटर के लिए जावा 5 की पूरी सुविधा को याद किया! –

+0

वापस जाने और कोड के माध्यम से गठबंधन करने के बाद, मैंने यह नहीं देखा था कि मैंने अपनी सार कक्षा में एक दूसरी getId() विधि परिभाषित की है (जाहिर है कि यह उदाहरण के मुकाबले कहीं अधिक जटिल था)। यह दूसरा मिलता है आईडी() जो एक एनम वापस स्विच स्टेटमेंट द्वारा बुलाया जा रहा था और मुझे गड़बड़ कर रहा था! –

+0

लिंक मृत लगता है। – FDinoff

8

यह जेनेरिक से संबंधित नहीं है। जावा में enum के लिए स्विच स्टेटमेंट केवल उस विशेष enum के मानों का उपयोग कर सकते हैं, इस प्रकार यह वास्तव में enum नाम निर्दिष्ट करने के लिए प्रतिबंधित है। यह काम करना चाहिए:

switch(event.getId()) { 
    case SELECTED: 
     l.selected(event); 
     break; 
    case SELECTION_CLEARED: 
     l.unselect(event); 
     break; 
} 

अद्यतन: ठीक है, यहाँ एक वास्तविक कोड है कि मैं कर दिया है कॉपी/पेस्ट किया था, संकलित और भाग गया है (जो मैं इसे कोई निर्भरता के साथ संकलित करने के लिए प्राप्त करने के लिए एक छोटा सा बदलना पड़ा) - कोई त्रुटि:

AbstractEvent.java

public abstract class AbstractEvent<S, T extends Enum<T>> { 
    private S src; 
    private T id; 

    public AbstractEvent(S src, T id) { 
     this.src = src; 
     this.id = id; 
    } 

    public S getSource() { 
     return src; 
    } 

    public T getId() { 
     return id; 
    } 
} 

MyEvent.java

public class MyEvent extends AbstractEvent<String, MyEvent.Type> { 
    public enum Type { SELECTED, SELECTION_CLEARED }; 

    public MyEvent(String src, Type t) { 
     super(src, t); 
    } 
} 

Test.java

public class Test { 
    public static void main(String[] args) { 
     fireEvent(new MyEvent("MyClass.myMethod", MyEvent.Type.SELECTED)); 
    } 

    private static void fireEvent(MyEvent event) { 
     switch(event.getId()) { 
      case SELECTED: 
       System.out.println("SELECTED"); 
       break; 
      case SELECTION_CLEARED: 
       System.out.println("UNSELECTED"); 
       break; 
     } 
    } 
} 

यह संकलित करता है तथा जावा 1.5 ठीक नीचे चलाता है। मुझे यहां क्या समझ नहीं आ रहा है?

+0

नहीं, मुझे डर है कि काम नहीं करता है। यदि वह मामला था तो यह मेरे मामले के बारे में शिकायत करेगा: रेखाएं और मेरी घटना नहीं .getId() एक स्विच स्टेटमेंट में। इसके अलावा, अगर मैं अपने कंक्रीट वर्ग में getId() को ओवरराइड करता हूं और केवल सुपर के getId() को सभी काम करता हूं। –

+0

मैं क्षमा चाहता हूं: मैंने उदाहरण में गलत टाइप किया है। आप निश्चित रूप से केस लेबल्स की योग्यता के बारे में सही हैं, हालांकि वास्तविक समस्या जो मुझे परेशान कर रही है, यही कारण है कि event.getId() मान्य स्विच-सक्षम पैरामीटर नहीं है। –

+0

यह निश्चित रूप से आपके कोड के साथ मेरे लिए काम करता है - कोई ओवरराइड नहीं। अब यदि 'fireEvent() 'को' सार तत्व 'के साथ पैरामीटर प्रकार के रूप में घोषित किया गया था, तो यह एक अलग कहानी होगी। – ChssPly76

2

बहुत संक्षेप में, क्योंकि टी एक Enum वर्ग के लिए मिटा दिया जाता है, न कि एक Enum निरंतर है, तो संकलित बयान लगता है कि आप इस हस्ताक्षर के रूप में, getID Enum होने का परिणाम पर स्विच कर रहे हैं:

Enum getId(); 

जब आप इसे किसी विशिष्ट प्रकार से ओवरराइड करते हैं, तो आप वापसी मान बदल रहे हैं और इसे चालू कर सकते हैं।

संपादित करें: प्रतिरोध मुझे उत्सुक बनाया है, इसलिए मैं कुछ कोड को कोसा:

public enum Num { 
    ONE, 
    TWO 
} 
public abstract class Abstract<T extends Enum<T>> { 
    public abstract T getId(); 
} 

public abstract class Real extends Abstract<Num> { 

} 

public static void main(String[] args) throws Exception { 
    Method m = Real.class.getMethod("getId"); 
    System.out.println(m.getReturnType().getName()); 
} 

परिणाम java.lang.Enum, अंक है नहीं। टी संकलन समय पर एनम को मिटा दिया जाता है, इसलिए आप इसे चालू नहीं कर सकते हैं।

संपादित करें:

मैं कोड नमूने हर किसी के साथ काम कर रहा है परीक्षण किया है, और वे, साथ ही मेरे लिए काम तो हालांकि मुझे लगता है कि यह और अधिक जटिल वास्तविक कोड में इस मुद्दे के आधार हैं, नमूना के रूप में वास्तव में तैनात संकलित और ठीक चलाता है।

+0

यह केवल तभी होगा जब हमारे पास 'सार तत्व' का कच्चा संदर्भ हो। – notnoop

+0

यही वह था जो मैं सोच रहा था - कि ऑटो-मुक्केबाजी कुछ कारणों से काम नहीं कर रही है - लेकिन महत्वपूर्ण सवाल क्यों है। –

+0

नहीं, फायरवेन्ट केवल कंक्रीट MyEvent कक्षा के साथ काम करता है। कोई भी सार तत्व से निपट रहा है - यह सिर्फ मेरे लिए एक सुविधा है। –

1

मैंने अभी यह कोशिश की है (आपके कोड को कॉपी-पेस्ट किया गया है) और मैं एक कंपाइलर त्रुटि को डुप्लिकेट नहीं कर सकता।

public abstract class AbstractEvent<S, T extends Enum<T>> 
{ 
    private S src; 
    private T id; 

    public AbstractEvent(S src, T id) 
    { 
     this.src = src; 
     this.id = id; 
    } 

    public S getSource() 
    { 
     return src; 
    } 

    public T getId() 
    { 
     return id; 
    } 
} 

और

public class MyEvent extends AbstractEvent<String, MyEvent.Type> 
{ 

    public enum Type 
    { 
     SELECTED, SELECTION_CLEARED 
    }; 

    public MyEvent(String src, Type t) 
    { 
     super(src, t); 
    } 


} 

और

public class TestMain 
{ 
    protected void fireEvent(MyEvent event) 
    { 
     switch (event.getId()) 
     { 
      case SELECTED: 
      break; 
      case SELECTION_CLEARED: 
      break; 
     } 
    } 
} 
2

वर्क्स मेरे लिए।

पूरा कट और पेस्ट परीक्षण कार्यक्रम:

enum MyEnum { 
    A, B 
} 
class Abstract<E extends Enum<E>> { 
    private final E e; 
    public Abstract(E e) { 
     this.e = e; 
    } 
    public E get() { 
     return e; 
    } 
} 
class Derived extends Abstract<MyEnum> { 
    public Derived() { 
     super(MyEnum.A); 
    } 
    public static int sw(Derived derived) { 
     switch (derived.get()) { 
      case A: return 1; 
      default: return 342; 
     } 
    } 
} 

आप कुछ विशेष संकलक का उपयोग कर रहे हैं?

+0

मैं ग्रहण के माध्यम से एक जावा 6 कंपाइलर (आर 14) का उपयोग कर रहा हूँ –