2013-06-12 17 views
5

मैं पहली बार लागू करता है कि आपूर्ति की इंटरफेसइस वर्ग की एक सुपर वर्ग के लिए एक सामान्य वर्ग के एक उपवर्ग निरुपित

public interface Finder<S extends Stack<T>,T extends Item> { 
    public S find(S s, int a); 
} 

public interface Stack<T extends Item> { 
    Stack<T> getCopy(); 
} 

और एक वर्ग की जोड़ी है:

मैं किसी भी नहीं बदल सकते हैं कार्यान्वयन को यथासंभव सामान्य बनाए रखने के दौरान कार्रवाई का सबसे अच्छा तरीका क्या होगा?

संपादित कुछ अन्य कोड जो मैं नहीं तोड़ सकता है को दर्शाता है SimpleFinder<ClassA,ClassB> तो मैं रूप में अच्छी तरह लागू करने में दो सामान्य प्रकार होना चाहिए।

+0

क्या हासिल करने के लिए कार्रवाई का सबसे अच्छा तरीका है? आप इंटरफेस परिभाषाओं को बदलने में असमर्थ क्यों हैं? – Bobulous

+0

ब्रूट कास्ट का प्रयास करें। इसे हल करने के तरीके हैं (रिकर्सिव टाइप पैरामीटर) लेकिन यह इसके लायक नहीं है। – ZhongYu

+0

@ अर्कनॉन क्योंकि यह मेरा परिवर्तन नहीं है ...: | और क्रूर कास्ट बहुत बदसूरत है ना? – SadStudent

उत्तर

3

समस्या यह है कि स्पष्ट रूप से Stack<T>S extends Stack<T> नहीं है। जावा दृढ़ता से टाइप किया गया है और आपको ऐसी चीजें करने नहीं देगा।

आप या तो Stack<T> पर जा सकते हैं, इस स्थिति में आपको अभी भी अनचेक रूपांतरण के बारे में चेतावनी मिलेगी। इसका मतलब है कि यह रूपांतरण असुरक्षित है।

public class SimpleFinder<S extends Stack<T>, T extends Item> implements Finder<S, T> { 

    @Override 
    public S find(S s, int a) { 
     Stack<T> stack = s.getCopy(); 
     return (S) stack; 
    } 

} 

या बस S extends Stack<T> के बजाय Stack<T> है, जो मेरी सिफारिश है का उपयोग करें:

public class SimpleFinder<T extends Item> implements Finder<Stack<T>, T> { 

    @Override 
    public Stack<T> find(Stack<T> s, int a) { 
     Stack<T> stack = s.getCopy(); 
     return stack; 
    } 

} 
+0

धन्यवाद! और हां, मैं इस बात से अवगत हूं कि यह काम नहीं कर रहा है, मुझे यकीन नहीं था कि सामान्यता को "खोने" के बिना इसे कैसे हल किया जाए: \ कारण मैं दूसरा समाधान नहीं कर सकता हूं कि एक और कोड है जो तत्काल नहीं है SimpleFinder और मैं इसे तोड़ नहीं सकता ... – SadStudent

+0

मैं दो तर्कों के लिए पूछ सकता हूं और ', टी>' भेज सकता हूं जैसे आपने इंटरफ़ेस को सुझाव दिया था, लेकिन फिर 'एस' अनावश्यक होगा और यह बदसूरत है भी, है ना? – SadStudent

+2

अनचेक कास्ट विकल्प असुरक्षित है - मैं इसे उत्तर से हटाने की सिफारिश करता हूं या कम से कम एक सार्थक अस्वीकरण जोड़ता हूं। –

0
public class SimpleFinder<S extends Stack<T>,T extends Item> implements Finder<S,T>{ 
    public S find(S s, int a){ 
     Stack<T> stack = ....; 
     ... 
     stack = s.getCopy(); 
     ..... 
     return (S) stack; 
    } 
} 

काम करना चाहिए। ध्यान रखें कि getCopy() वापसी प्रकार से मेल खाने के लिए स्टैक Stack<T> और S नहीं होना चाहिए। मुझे उम्मीद है कि S ठीक होने के लिए टाइप करें, क्योंकि यह Stack<T> तक फैला है, लेकिन इसे लागू करना यह व्यवहार है जिसे मैं देख रहा हूं।

+0

यह संकलित नहीं करता है ... – m0skit0

+0

क्षमा करें, मैंने अभी संपादित किया है, मुझे आशा है कि यह अभी ठीक है। –

+0

नोप अभी भी संकलित नहीं करता है: "विधि के लिए वापसी प्रकार गुम है"। वह वापसी प्रकार वैध नहीं है (जावा 7 तक)। – m0skit0

0

आपका प्रकार SStack<T> की एक उप-प्रकार है, लेकिन प्रति विधि upcasting यह एक Stack<T> करने के लिए Stack<T> के किसी भी उप-प्रकार हो सकता है। आपको प्रतिलिपि का परिणाम S

2

जब से तुम इंटरफेस बदल नहीं सकते, तो आप कोई चारा नहीं जानवर डाली क्या करना है।

अधिक सामान्य चर्चा में, हमें यहां "स्वयं प्रकार" की आवश्यकता है, हम यह कहना चाहते हैं कि एक विधि आमंत्रण foo.bar() को स्थिर प्रकार foo वापस करना चाहिए। आम तौर पर स्वयं का प्रकार धाराप्रवाह एपीआई के लिए चाहता था जहां विधि foo खुद को वापस करनी चाहिए। आपके मामले में आप एक नई वस्तु वापस करना चाहते हैं।

जावा में स्वयं प्रकार के लिए कोई संतोषजनक उत्तर नहीं है। एक चाल स्वयं संदर्भित प्रकार पैरामीटर जैसे Foo<T extends Foo<T>> के माध्यम से है, हालांकि यह बहुत बदसूरत है, और यह वास्तव में यह लागू नहीं कर सकता कि कोई सबटाइप BarFoo<Bar> होना चाहिए। और यह चाल आपके मामले में बिल्कुल मदद नहीं करेगी।

एक और चाल

public interface Stack<T extends Item> { 
    <X extends Stack<T>> X getCopy(); 
} 

यहाँ काम कर सकते हैं, फोन करने वाले सटीक वापसी प्रकार आपूर्ति करती है।

 S stack = ....; 
    ... 
    stack = s.getCopy(); 
    // compiles, because X is inferred to be S 

यह चाल कॉल साइटों को सरल बनाने में मदद करती है।हालांकि getCopy() के कार्यान्वयन में छिपा हुआ ब्रूट कास्ट अभी भी मौजूद है। यह चाल खतरनाक है और कॉलर को पता होना चाहिए कि यह क्या कर रहा है। व्यक्तिगत रूप से मैं यह नहीं करूँगा; फोर्स कॉलर के लिए कलाकारों के लिए बेहतर है।

1

के रूप में टिप्पणी में चर्चा की, अपने डिजाइन जरूरी है कि getCopy विधि "आत्म प्रकार" वापसी - जो है, एक BlueStack<T> कार्यान्वयन अपने getCopy से एक BlueStack<T> वापसी की उम्मीद की जाएगी, और RedStack<T> एक RedStack<T> आदि

लौटना चाहिए

दुर्भाग्यवश, जावा में "स्वयं प्रकार" व्यक्त करने का कोई तरीका नहीं है। के रूप में zhong.j.yu points out, एक पुनरावर्ती प्रकार पैरामीटर, करीब आता है उदाहरण के लिए:

//not recommended! 
public interface Stack<S extends Stack<S, T>, T extends Item> { 
    S getCopy(); 
} 

लेकिन जैसे zhong.j.yu का उल्लेख इस unintuitive है और अभी भी "झूठ बोल" और लौटने से एक BlueStack<T> को रोकने के लिए विफल हो जाएगा getCopy से।

इसके बजाय, मैं एक नया स्वरूप की अनुशंसा करता हूं। Stack से स्वयं के ढेर की प्रतिलिपि बनाने की ज़िम्मेदारी को कम करने का प्रयास करें। उदाहरण के लिए:

public interface StackCopier<S extends Stack<T>, T extends Item> { 

    S copy(S original); 
} 

StackCopier के कार्यान्वयन उनके संबंधित Stack के निजी सदस्यों के लिए उपयोग की जरूरत है, उन्हें नेस्टेड कक्षाएं बनाने पर विचार, उदाहरण के लिए:

class BlueStack<T extends Item> implements Stack<T> { 

    ... 

    static class Copier<T extends Item> implements StackCopier<BlueStack<T>, T> { 

     @Override 
     public BlueStack<T> copy(BlueStack<T> original) { 

      ... 
     } 
    } 
पाठ्यक्रम SimpleFinder के

को परिवर्तित करने की आवश्यकता होगी या तो एक StackCopier<S, T> क्षेत्र है या find का एक नया पैरामीटर के रूप में एक ले:

private final StackCopier<S, T> copier = ...; 

public S find(S stack, int a) { 

    S stackCopy = copier.copy(stack); 

    ... 

    return stackCopy; 
} 
+0

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

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