2010-07-19 17 views
11

एक अमूर्त वर्ग के साथ साथ उपवर्ग मैं एक विधि है कि रिटर्न "इस" उपवर्गों के लिए निर्धारित करना चाहते हैं:रिटर्निंग एक वस्तुओं जेनरिक

CakeEater phil = new CakeEater(); 
phil.eat("wacky cake").eat("chocolate cake").eat("banana bread"); 
:

public abstract class Foo { 
    ... 
    public <T extends Foo> T eat(String eatCake) { 
     ... 
     return this; 
    } 
} 

public class CakeEater extends Foo {} 

मैं जैसे कार्य करने में सक्षम होना चाहते

तर्कसंगत रूप से केले की रोटी एक अवैध अर्ग्यूमेंट अपवाद को "एक केक नहीं" संदेश के साथ फेंक देगा!

उत्तर

13
public abstract class Foo<T extends Foo<T>> // see ColinD's comment 
{ 
    public T eat(String eatCake) 
    { 
     return (T)this; 
    } 
} 

public class CakeEater extends Foo<CakeEater> 
{ 
    public void f(){} 
} 

संपादित

एक में उपवर्ग व्यवहार की आवश्यकता के लिए कोई समस्या नहीं है निश्चित तरीका जो स्थिर टाइपिंग की जांच कर सकता है उससे परे है। हम हर समय ऐसा करते हैं - सादे अंग्रेजी के पेज और पेज यह निर्दिष्ट करने के लिए कि आप उप-वर्ग कैसे लिखते हैं।

कॉन्वेंट रिटर्न प्रकार के साथ अन्य प्रस्तावित समाधान, एक ही करना चाहिए - सादे अंग्रेजी में, सबक्लास लागूकर्ताओं से पूछना, this के प्रकार को वापस करने के लिए। उस आवश्यकता को स्थिर टाइपिंग द्वारा निर्दिष्ट नहीं किया जा सकता है।

+1

होना चाहिए 'Foo >' बढ़ाता है। यह काम करता है, यद्यपि आप आसानी से एक कक्षा बना सकते हैं जो 'क्लासकास्ट अपवाद' के साथ उड़ाएगा जब आप 'खाने' कहते हैं, जैसे 'कक्षा बार Foo ' बढ़ाता है। – ColinD

+0

यह वह समाधान है जिसका मैंने उपयोग समाप्त किया, लेकिन आप देखेंगे कि रिटर्न में एक अनचेक कास्ट चेतावनी है। तर्कसंगत रूप से यह समझ में आता है कि हम टी को डाल सकते हैं क्योंकि यह टी – Sarabjot

+2

हां का उप-वर्ग है।एक बेहतर दुनिया में, जावा में 'यह' प्रकार हो सकता है, जो कई मामलों में बहुत उपयोगी होगा। – irreputable

5

मैं तुम्हें जेनरिक जावा 5 (और बाद में) की जरूरत नहीं लगता कि covariant वापसी प्रकार, जैसे हैं:

public abstract class Foo { 
    ... 
    public Foo eat(String eatCake) { 
     ... 
     return this; 
    } 
} 

public class CakeEater extends Foo { 

    public CakeEater eat(String eatCake) { 
     return this; 
    } 
} 
+0

यदि यह सुपरक्लास में पूरी तरह से परिभाषित किया गया है तो यह सबक्लास में परिभाषित करने के लिए अनावश्यक कोड बनाता है; यह सुपरक्लास को कॉल कर सकता है लेकिन यह अनावश्यक लगता है। यह काम करता है अगर आप इसे टाइप टी के रूप में डालें और चेतावनियों को दबाएं। – Sarabjot

+0

यह काम करता है अगर आप इसे टाइप टी के रूप में डालें और चेतावनियों को दबाएं। कारण यह उपवर्ग के प्रकार वापसी होना चाहिए क्योंकि: methodTakesCakeEater ((नई CakeEater) .eat ("केक") खाने ("पाई"); methodTakesCakeEater एक CakeEater पैरामीटर की जरूरत है – Sarabjot

+5

तो एक।। समाधान में '@ SuppressWarnings' शामिल है, इसे समाधान नहीं माना जाना चाहिए। बस मेरे दो सेंट। – whiskeysierra

15

क्लाइंट प्वाइंट व्यू (जो आम तौर पर आप लेना चाहते हैं) से स्वादपूर्ण दृष्टिकोण है, जेनरिक बार्कर बताते हुए, जेनेरिकों का समर्थन करने के लिए जोड़ा गया कॉन्वेंट रिटर्न प्रकारों का उपयोग करना है।

थोड़ा कम सुस्वादु, लेकिन अधिक स्वादिष्ट है कि एक डाली एक getThis विधि जोड़ने के लिए है:

protected abstract T getThis(); 

public <T extends Foo> T eat(String eatCake) { 
    ... 
    return getThis(); 
} 
0

एक दृष्टिकोण है कि मैंने पहले का उपयोग किया है समान व्यवहार को प्राप्त करने के उपवर्ग एक में अपने प्रकार से पारित करने के लिए है (जेनरेटेड) पैरेंट प्रकार का निर्माता। अस्वीकरण के माध्यम से मैं फ्लाई पर उप-वर्गों का निर्माण कर रहा था और मेरी कोड पीढ़ी को सरल रखने के लिए उत्तराधिकारी धोखाधड़ी का थोड़ा सा था, क्योंकि हमेशा मेरा पहला वृत्ति पूरी तरह से रिश्ते को दूर करने की कोशिश करना है।

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