2015-03-09 13 views
11

मैं निम्नलिखित सरल उदाहरण में मेरी समस्या को वर्णन करने की कोशिश करेंगे:मैं एकल बाधा में विधि और वर्ग प्रकार पैरामीटर दोनों का उपयोग कैसे कर सकता हूं?

public class DataHolder<T> { 
    private final T myValue; 

    public DataHolder(T value) { 
    myValue = value; 
    } 

    public T get() { 
    return myValue; 
    } 

    // Won't compile 
    public <R> DataHolder<R super T> firstNotNull(DataHolder<? extends R> other) { 
    return new DataHolder<R>(myValue != null ? myValue : other.myValue);  } 

    public static <R> DataHolder<R> selectFirstNotNull(DataHolder<? extends R> first, 
                DataHolder<? extends R> second) { 
    return new DataHolder<R>(first.myValue != null ? first.myValue : second.myValue); 
    } 
} 

यहाँ मैं this और other तर्क के T, इसलिए सामान्य विधि firstNotNull कि DataHolder प्रकार पैरामीटर के आम महाप्रकार द्वारा parametrized रिटर्न लिखना चाहते हैं बाद में मैं लिख सकता था उदाहरण के लिए

DataHolder<Number> r = new DataHolder<>(3).firstNotNull(new DataHolder<>(2.0)); 

या

DataHolder<Object> r = new DataHolder<>("foo").firstNotNull(new DataHolder<>(42)); 

समस्या यह है कि firstNotNull की इस परिभाषा संदेश के साथ संकलक द्वारा अस्वीकार कर दिया है कि प्रकार बाधा के super T हिस्सा अवैध (वाक्य रचना) है। हालांकि इस बाधा परिभाषा के बिना भी गलत (स्पष्ट रूप से) है, क्योंकि इस मामले में T और R एक-दूसरे से असंबंधित नहीं हैं।

दिलचस्प बात यह है कि समान स्थिर विधि selectFirstNotNull की परिभाषा सही है और बाद में अपेक्षित कार्य करता है। क्या जावा टाइप सिस्टम में गैर स्थैतिक तरीकों के साथ समान लचीलापन हासिल करना संभव है?

+0

DataHolder । यह वाक्य रचनात्मक रूप से संभव नहीं है। इसके अलावा, यह स्थिर बनाम गैर स्थैतिक बाधाओं के बारे में कोई सवाल नहीं है। स्थैतिक और गैर स्थैतिक विधि टाइप पैरामीटर के संबंध में समान नहीं हैं। – CKing

+0

ऐसा लगता है कि सुपर वाइल्डकार्ड का उपयोग प्रकार के साथ नहीं किया जा सकता है, और इसका उपयोग केवल , मैं इसके बारे में भी निश्चित नहीं हूं। – Artemkller545

उत्तर

6

ऐसा करना संभव नहीं है। Guava के लेखक Optional.or के साथ एक ही समस्या में भाग गए।

जेनरिक के बारे में ध्यान दें:: हस्ताक्षर public T or(T defaultValue) अधिक प्रतिबंधात्मक है कि विधि के दस्तावेज़ से। हालांकि, आदर्श हस्ताक्षर, public <S super T> S or(S), कानूनी जावा नहीं है। नतीजतन, कुछ समझदार संचालन शामिल उपप्रकार संकलन त्रुटियाँ हैं:

Optional<Integer> optionalInt = getSomeOptionalInt(); 
Number value = optionalInt.or(0.5); // error 

FluentIterable<? extends Number> numbers = getSomeNumbers(); 
Optional<? extends Number> first = numbers.first(); 
Number value = first.or(0.5); // error 

समाधान के लिए, यह हमेशा एक Optional<? extends T> to Optional<T> कास्ट करने के लिए सुरक्षित है।Optional<Number> (जहां Number वांछित आउटपुट प्रकार है) करने के लिए Optional उदाहरणों से ऊपर उदाहरण के दोनों कास्टिंग समस्या का हल:

Optional<Number> optionalInt = (Optional) getSomeOptionalInt(); 
Number value = optionalInt.or(0.5); // fine 

FluentIterable<? extends Number> numbers = getSomeNumbers(); 
Optional<Number> first = (Optional) numbers.first(); 
Number value = first.or(0.5); // fine 

DataHolder के बाद से Optional तरह अपरिवर्तनीय है, ऊपर वैकल्पिक हल भी आप के लिए काम करेंगे।

यह भी देखें: Rotsor's answer to Bounding generics with 'super' keyword

+0

में संकलित नहीं है धन्यवाद! वास्तव में मुझे पहले स्थान पर अमरूद के 'वैकल्पिक' के बारे में सोचना चाहिए था। खैर, ऐसा लगता है कि मैं अंत में @ रोहित-जैन द्वारा सुझाए गए अधिक प्रतिबंधक संस्करण का उपयोग करूंगा, अगर Google में भी लोगों को यह नहीं पता था कि इस सीमा को बेहतर तरीके से कैसे निपटाना है। – east825

4

मुझे नहीं लगता कि ऐसा करने के लिए कोई आसान और प्रकार-सुरक्षित तरीका है। मैं दृष्टिकोण की एक जोड़ी की कोशिश की है, लेकिन केवल काम कर रहे दृष्टिकोण है कि मैंने पाया एक super प्रकार सामान्य उदाहरण के साथ शुरू, और विधि बहुत इस तरह सरल बनाने के लिए है:

public DataHolder<T> firstNotNull(DataHolder<? extends T> other) { 
    return new DataHolder<T>(myValue != null ? myValue : other.myValue); 
} 

अब आप अपने मंगलाचरण बदलना होगा करने के लिए:

DataHolder<Number> r = new DataHolder<Number>(3).firstNotNull(new DataHolder<>(2.0)); 

आप तर्क दे सकते हैं कि यह वास्तव में आपके प्रश्न का उत्तर नहीं है, लेकिन यह एक static विधि दृष्टिकोण करने का सबसे सरल बात आप प्राप्त करने के लिए जा रहे हैं, या बेहतर स्थल है। आप निश्चित रूप से ऐसा करने के लिए कुछ अत्यधिक संकलित (और प्रकार-असुरक्षित) विधियों के साथ आ सकते हैं, लेकिन पठनीयता यहां बड़ी चिंता का होना चाहिए।

+4

@Downvoter: टिप्पणी करने की देखभाल? –

0

अपने विधि को बदलने के रूप में इस प्रयास करें:

 public <R> DataHolder<R> firstNotNull(DataHolder<? super T> other) { 
     return new DataHolder<R>((R)(this.myValue != null ? myValue : other.myValue)); 
    } 

चेतावनी: यह संकलित और ठीक से अधिकांश भाग के लिए जाँच की जा रही की उपस्थिति देता है, लेकिन सही नहीं है। यह इनपुट पैरामीटर को प्रतिबंधित करेगा, लेकिन आउटपुट नहीं। यह पूरी तरह से नहीं किया जा सकता है। कुछ तरीकों से आप चेक किए जाने के भ्रम को देने के बजाय इस अनचेक करने से बेहतर हो सकते हैं। यहां कुछ उदाहरण दिए गए हैं:

 DataHolder<BigDecimal> a = new DataHolder<>(new BigDecimal(34.0)); 
     DataHolder<Number> b = new DataHolder<>(new Integer(34)); 
     DataHolder<String> c = new DataHolder<>(""); 
     DataHolder<Number> p = a.firstNotNull(b); // WORKS (good) 
     DataHolder<BigDecimal> q = b.firstNotNull(a); // FAILS (good) 
     DataHolder<BigDecimal> r = b.firstNotNull(c); // FAILS (good) 
     DataHolder<String> s = a.firstNotNull(b); // WORKS (not good!!!) 
+1

क्या आपने इस विधि के साथ विधि आमंत्रण संकलित करने का प्रयास किया था? काम नहीं करता –

+1

मैंने किया और यह मेरे लिए संकलित करता है। यह एक अनचेक चेतावनी देता है, जिसे आसानी से दबाया जा सकता है, लेकिन यह संकलित करता है। आप किस जावा संस्करण का उपयोग कर रहे हैं? – Necreaux

+0

जावा 8. यह संकलित नहीं हुआ .. –

संबंधित मुद्दे

 संबंधित मुद्दे