2015-11-23 10 views
13

जावा 8 में, यदि मेरे पास अलग-अलग (लेकिन संगत) रिटर्न प्रकारों के साथ दो इंटरफेस हैं, तो प्रतिबिंब मुझे बताता है कि दो तरीकों में से एक डिफ़ॉल्ट विधि है, भले ही मैंने वास्तव में विधि को डिफ़ॉल्ट या प्रदान नहीं किया है एक विधि शरीरजब दो इंटरफेस में विरोधाभासी रिटर्न प्रकार होते हैं, तो एक विधि डिफ़ॉल्ट क्यों होती है?

उदाहरण के लिए, निम्नलिखित कोड का टुकड़ा ले:

package com.company; 
import java.lang.reflect.Method; 

interface BarInterface {} 
class Bar implements BarInterface {} 

interface FooInterface { 
    public BarInterface getBar(); 
} 

interface FooInterface2 extends FooInterface { 
    public Bar getBar(); 
} 

class Foo implements FooInterface2 { 
    public Bar getBar(){ 
     throw new UnsupportedOperationException(); 
    } 
} 

public class Main { 
    public static void main(String[] args) { 
     for(Method m : FooInterface2.class.getMethods()){ 
      System.out.println(m); 
     } 
    } 
} 

जावा 1.8 निम्नलिखित उत्पादन का उत्पादन:

public abstract com.company.Bar com.company.FooInterface2.getBar() 
public default com.company.BarInterface com.company.FooInterface2.getBar() 

यह अजीब लगता है न केवल क्योंकि दोनों तरीकों मौजूद हैं, बल्कि इसलिए भी कि एक विधियों का अचानक और अस्पष्ट रूप से डिफ़ॉल्ट विधि बन गया है।

जावा 7 में एक ही कोड चल रहा है कुछ थोड़ा कम अप्रत्याशित, अभी भी भ्रमित हालांकि पैदावार, यह देखते हुए कि दोनों तरीकों में एक ही हस्ताक्षर है:

public abstract com.company.Bar com.company.FooInterface2.getBar() 
public abstract com.company.BarInterface com.company.FooInterface.getBar() 

जावा निश्चित रूप से कई वापसी प्रकार का समर्थन नहीं करता है, तो यह परिणाम अभी भी बहुत अजीब है।


स्पष्ट अगले सोचा है: "ठीक है, तो हो सकता है यह एक विशेष व्यवहार है कि केवल इंटरफेस पर लागू होता है, क्योंकि इन तरीकों कोई कार्यान्वयन है।"

गलत।

class Foo2 implements FooInterface2 { 
    public Bar getBar(){ 
     throw new UnsupportedOperationException(); 
    } 
} 

public class Main { 
    public static void main(String[] args) { 
     for(Method m : Foo2.class.getMethods()){ 
      System.out.println(m); 
     } 
    } 
} 

public com.company.Bar com.company.Foo2.getBar() 
public com.company.BarInterface com.company.Foo2.getBar() 

यहाँ क्या हो रहा है पैदावार? जावा इन्हें अलग-अलग तरीकों के रूप में क्यों समझा रहा है, और इंटरफ़ेस विधियों में से कोई एक कार्यान्वयन के साथ एक डिफ़ॉल्ट विधि कैसे बन गया है?

उत्तर

9

यह आपके द्वारा प्रदान की जाने वाली default विधि नहीं है बल्कि एक ब्रिजिंग विधि है। आपके द्वारा परिभाषित मूल इंटरफ़ेस में।

public BarInterface getBar(); 

और आपके पास एक विधि होनी चाहिए जिसे इसे लागू किया जा सके।

उदा

FooInterface fi = new Foo(); 
BarInterface bi = fi.getBar(); // calls BarInterface getBar() 

हालांकि, अगर आप भी यह सह संस्करण वापसी प्रकार है कॉल करने के लिए सक्षम होना चाहिए।

FooInterface2 fi = new Foo(); 
Bar bar = fi.getBar(); // calls Bar getBar() 

ये वही विधि हैं, केवल अंतर यह है कि कोई दूसरा कॉल करता है और वापसी मूल्य डालता है। यह तरीका है जो default कार्यान्वयन प्रतीत होता है क्योंकि यह इंटरफ़ेस पर है जो यह करता है।

नोट: यदि आपके पास इंटरफ़ेस/कक्षा के कई स्तर हैं और प्रत्येक के पास एक अलग रिटर्न प्रकार है, तो विधियों की संख्या एकत्रित होती है।

इसका कारण यह है कि JVM अलग-अलग रिटर्न प्रकार के साथ कई विधियों की अनुमति देता है क्योंकि रिटर्न प्रकार हस्ताक्षर का हिस्सा है।मुझे कॉलर को यह बताने की ज़रूरत है कि किस रिटर्न प्रकार की उम्मीद है और जेवीएम वास्तव में सह-प्रकार के रिटर्न प्रकारों को समझ नहीं पाता है।

+0

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

+1

@schmod मैंने अपना जवाब अपडेट किया है। 'Javac' जावा को ऐसा करने के तरीकों को जोड़ता है जो जावा को वास्तव में संस्करणों के बीच JVM को बदलने के बिना आवश्यक है। जैसे अन्य वर्गों में 'निजी' सदस्यों तक पहुंचने से यह भी होता है। JVM के लिए, रिटर्न प्रकार हस्ताक्षर का हिस्सा है। हाल ही में ओरेकल के तहत जेवीएम को बदलने की कुछ इच्छा रही है, लेकिन ज्यादा नहीं। –

+0

उम्म .. लेकिन क्यों उस पुल विधि को उत्पन्न करने की आवश्यकता है। 'बार' लौटने वाली कोई भी विधि 'BarInterface' संदर्भ प्रकार को असाइन की जा सकती है। साथ ही, मैंने सोचा कि वापसी का प्रकार विधि हस्ताक्षर का हिस्सा नहीं है। क्या आपका मतलब कुछ और था? –

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

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