2013-09-06 7 views
5

में ब्रिजिंग तकनीक का उपयोग कर covariant अधिभावी पर पढ़ते समय लागू किया गया है, मैं बहुत ही अजीब तथ्य का पता लगाना,कैसे covariant विधि अधिभावी जावा

covariant विधि अधिभावी एक ब्रिजिंग तकनीक का उपयोग कर कार्यान्वित किया जाता है। यह भी कहा कि इस सुविधा Java5 में लागू और इसके बाद के संस्करण है। (मुझे लगता है कि ऐसा इसलिए है क्योंकि Java5 से शुरू जेनरिक)

यह कैसे happens.Please मुझे उदाहरण के साथ मदद।

public interface Shape<T extends Shape<T>> { 
    T getType(); 
    void setType(T type); 
} 

public class Circle implements Shape<Circle> { 
    Circle getType() { } 
    void setType(Circle circle) { } 
} 

यह अब तक अच्छा लग रहा है:

उत्तर

7

एक उदाहरण पर विचार करें। लेकिन, टाइप एरर के बाद, इंटरफेस इसे सामान्य प्रकार खो देता है, और टाइप T को ऊपरी बाउंड के साथ बदल दिया जाता है। तो इंटरफ़ेस और क्लास इस तरह दिखता है:

public interface Shape { 
    Shape getType(); 
    void setType(Shape type); 
} 

public class Circle implements Shape { 
    Circle getType() { } 
    void setType(Circle circle) { } 
} 

अब, समस्या है। मिटाए जाने के बाद Circle में विधि वास्तव में Shape का ओवरराइड संस्करण नहीं है। ध्यान दें कि, अब जिस तरीके से दिखता है, वह पैरामीटर पर अधिक प्रतिबंध लागू करता है, और यह मान देता है। ऐसा इसलिए है क्योंकि मिरर इंटरफ़ेस में विधि के हस्ताक्षर को बदलता है।

इस समस्या को हल करने के लिए, कंपाइलर उन लोगों के लिए पुल विधि जोड़ता है, जो कक्षा में उन वास्तविक तरीकों को कॉल का प्रतिनिधित्व करता है।

तो, वर्ग वास्तव में बदल जाती है:

public class Circle implements Shape { 
    Circle getType() { } 
    void setType(Circle circle) { } 

    // Bridge method added by compiler. 
    Shape getType() { return getType(); } // delegate to actual method 
    void setType(Shape shape) { setType((Circle)shape); } // delegate to actual method 
} 

तो, पुल विधि अब इंटरफ़ेस में तरीकों में से ओवरराइड संस्करण है, और वे वास्तविक तरीका है कि काम करता है के लिए कॉल प्रतिनिधि ।

ध्यान दें कि पुल विधि में उपयोग किया जाने वाला प्रकार इंटरफ़ेस के प्रकार पैरामीटर का मिटा है, इस मामले में Shape


संदर्भ:

+0

बहुत रोचक! और दो विधियों के कारण कोई त्रुटि नहीं है जिसमें एक ही कक्षा के समान नाम/पैरामीटर हैं? अर्थात। "सर्कल" संदेश में डुप्लिकेट विधि getType()? – sp00m

+0

@ sp00m: यदि आप जावा कंपाइलर को पास करने का प्रयास करते हैं तो एक त्रुटि होगी, क्योंकि विधियां केवल रिटर्न प्रकार से भिन्न नहीं हो सकती हैं। लेकिन JVM बाइटकोड स्तर पर, वह प्रतिबंध मौजूद नहीं है। – mhsmith

1

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

उदाहरण 1: वापसी प्रकार में सहप्रसरण भी, भले ही कोई जेनरिक मौजूद हैं सिंथेटिक पुल तरीकों का उपयोग कर कार्यान्वित किया जाता है।

उदाहरण के लिए:

abstract class A {  

    public abstract A get(); 
} 

class B extends A { 

    @Override 
    public B get() { 
    return this; 
    } 
} 

एक कृत्रिम पुल विधि है कि मूल विधि के प्रतिनिधियों का उपयोग कर संकलक द्वारा बाईटकोड में लागू किया जाएगा। सिद्धांत रूप में आप कल्पना कर सकते है कि संकलक इस के लिए covariant ओवरराइड अनुवाद:

abstract class A {  

    public abstract A get(); 
} 

class B extends A { 

    //bytecode only bridge method 
    @Override 
    public A get() { 
    return get; 
    } 

    public B get() { 
    return this; 
    } 
} 

उदाहरण 2 - जेनेरिक्स: चलो एक उदाहरण देखें, जब जेनरिक शामिल कर रहे हैं।

abstract class A<T> {  

    public abstract T get(); 
} 

class B extends A<String> { 

    @Override 
    public String get() { 
    return "hello"; 
    } 
} 

विधि get() वर्ग B के वर्ग A में विधि get को वापसी प्रकार में covariant है। कोड के इस बिट को संकलित करते समय संकलक मिटा देगा जिसका अर्थ है कि यह जेनरिक को अपनी सीमाओं से प्रतिस्थापित करेगा और यह सुनिश्चित करने के लिए कि सब कुछ काम करता है, को जोड़ देगा।

विलोपन के बाद कक्षाएं इस तरह दिखेगा:

abstract class A { 

    public abstract Object get(); 
} 

class B extends A { 

    @Override 
    public String get() { 
    return "hello"; 
    } 
} 

अब के बाद से get की विधि हस्ताक्षर public Object get() है जो एक हस्ताक्षर है कि मौजूद है वर्ग B में संकलक वर्ग B में एक पुल विधि में उत्पन्न होगा नहीं है ओवरराइडिंग प्राप्त करने के लिए आदेश।

आप कक्षा B के बारे में सोच सकते हैं नीचे दिये गये दिख रहे हैं। हालांकि, यह ध्यान रखना महत्वपूर्ण है कि नीचे दिया गया कोड कभी नहीं बनाया जाएगा। यह संकलित नहीं होगा। कंपाइलर बाइटकोड में समकक्ष get विधि उत्पन्न करता है।

class B extends A { 

    //bridge method 
    @Override 
    public Object get() { 
    return get(); 
    } 

    public String get() { 
    return "hello"; 
    } 
} 

हर बहुरूपी कि get invokes पुल तरीका है जिसके वास्तविक प्राप्त विधि प्रतिनिधि होगा लागू करेगा A के माध्यम से वर्ग B का उपयोग।

1

निम्नलिखित दो वर्गों को देखते हुए:

public class Node<T> { 
    private T data; 
    public Node(T data) { this.data = data; } 

    public void setData(T data) { 
     System.out.println("Node.setData"); 
     this.data = data; 
    } 
} 

public class MyNode extends Node<Integer> { 
    public MyNode(Integer data) { 
super(data); } 
    public void setData(Integer data) { 
     System.out.println("MyNode.setData"); 
     super.setData(data); 
    } 
} 

जब क्लास अथवा अंतरफलक है कि एक पैरामिट्रीकृत वर्ग फैली या एक पैरामिट्रीकृत इंटरफ़ेस लागू करता संकलन, संकलक, एक कृत्रिम विधि बनाने के लिए आवश्यकता हो सकती है एक पुल विधि कहा जाता है, के रूप में प्रकार मिटाने की प्रक्रिया का हिस्सा।

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

class MyNode extends Node { 

    // Bridge method generated by the compiler 
    // 
    public void setData(Object data) { 
     setData((Integer) data); 
    } 

    public void setData(Integer data) { 
     System.out.println("MyNode.setData"); 
     super.setData(data); 
    } 

    // ... 
} 
संबंधित मुद्दे