एक असंबंधित इंटरफ़ेस प्रकार के साथ इनवॉइस करने पर कंपाइलर क्लास प्रकार के पैरामीटर के साथ इस जेनेरिक पद्धति को क्यों चुनता है?


11

निम्नलिखित दो वर्गों और इंटरफ़ेस पर विचार करें:

public class Class1 {}
public class Class2 {}
public interface Interface1 {}

क्यों दूसरी कॉल करने के लिए करता है mandatoryके साथ अतिभारित विधि आह्वान Class2, अगर getInterface1और Interface1साथ कोई संबंध नहीं है Class2?

public class Test {

    public static void main(String[] args) {
        Class1 class1 = getClass1();
        Interface1 interface1 = getInterface1();

        mandatory(getClass1());     // prints "T is not class2"
        mandatory(getInterface1()); // prints "T is class2"
        mandatory(class1);          // prints "T is not class2"
        mandatory(interface1);      // prints "T is not class2"
    }

    public static <T> void mandatory(T o) {
        System.out.println("T is not class2");
    }

    public static <T extends Class2> void mandatory(T o) {
        System.out.println("T is class2");
    }

    public static <T extends Class1> T getClass1() {
        return null;
    }

    public static <T extends Interface1> T getInterface1() {
        return null;
    }
}

मैं समझता हूं कि जावा 8 ने जावा 7 के साथ संगतता को तोड़ दिया था :

$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac -source 1.7 -target 1.7 *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
T is not class2
T is not class2
T is not class2
T is not class2

और जावा 8 के साथ (11 और 13 के साथ भी परीक्षण किया गया):

$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test                        
T is not class2
T is class2
T is not class2
T is not class2

1
निचला रेखा: जावा में ओवरलोडिंग विधि बहुत सारे आश्चर्य लाती है, इसका उपयोग केवल अत्यधिक देखभाल के साथ किया जाना चाहिए। केवल एक प्रकार के पैरामीटर के एक बाउंड द्वारा दो अधिभार को हटाते हुए, परेशानी के लिए पूछ रहा है, जैसा कि उत्तर की जटिलता द्वारा दर्शाया गया है। आप मूल रूप से अपने कोड के प्रत्येक पाठक को उस कोड को पढ़ने और समझने के लिए कह रहे हैं, इससे पहले कि वे आपके कोड को समझ सकें। अलग तरह से रखें: यदि आपका प्रोग्राम टूट जाता है जब प्रकार की सुरक्षा में सुधार होता है, तो आप सुरक्षित क्षेत्र में नहीं हैं। सौभाग्य!
Stephan Herrmann

जवाबों:


4

प्रकार के अनुमान के नियमों को जावा 8 में एक महत्वपूर्ण ओवरहाल मिला है, विशेष रूप से लक्ष्य प्रकार के अनुमान में बहुत सुधार हुआ है। तो, जबकि जावा 8 से पहले विधि तर्क साइट किसी भी निष्कर्ष, मिट प्रकार (करने के लिए दोषी प्राप्त नहीं किया था Class1के लिए getClass1()और Interface1के लिए getInterface1()), जावा 8 में सबसे विशिष्ट लागू प्रकार मान लिया जाता है। जावा 8 के लिए JLS ने एक नया अध्याय अध्याय 18 पेश किया। प्रकारांतर जो कि जावा 7 के लिए JLS में गायब है।


के लिए सबसे विशिष्ट लागू प्रकार <T extends Interface1>है <X extends RequiredClass & BottomInterface>, जहां RequiredClassएक संदर्भ के लिए आवश्यक एक वर्ग है, और BottomInterfaceसभी इंटरफेस (सहित Interface1) के लिए एक निचला प्रकार है ।

नोट: प्रत्येक जावा प्रकार के रूप में प्रतिनिधित्व किया जा सकता है SomeClass & SomeInterfaces। चूंकि RequiredClassउप-प्रकार है SomeClass, और BottomInterfaceउप-प्रकार है SomeInterfaces, Xप्रत्येक जावा प्रकार का उप-प्रकार है। इसलिए, Xएक जावा नीचे प्रकार है।

Xजावा नीचे प्रकार के बाद से दोनों public static <T> void mandatory(T o)और public static <T extends Class2> void mandatory(T o)विधियों के हस्ताक्षर मेल खाते हैं X

इसलिए, .1215.12.2 के अनुसार , विधि mandatory(getInterface1())का सबसे विशिष्ट अतिभार कहा जाता है mandatory(), जो public static <T extends Class2> void mandatory(T o)तब <T extends Class2>से अधिक विशिष्ट है <T>

यहां बताया गया है कि आप विधि हस्ताक्षर से getInterface1()मेल खाने वाले परिणाम को वापस करने के लिए स्पष्ट रूप से टाइप पैरामीटर निर्दिष्ट कर सकते हैं public static <T extends Class2> void mandatory(T o):

public static <T extends Class2 & Interface1> void helper() {
    mandatory(Test.<T>getInterface1()); // prints "T is class2"
}

के लिए सबसे विशिष्ट लागू प्रकार <T extends Class1>है <Y extends Class1 & BottomInterface>, जहां BottomInterfaceसभी इंटरफेस के लिए एक निचला प्रकार है।

Ypublic static <T> void mandatory(T o)विधि हस्ताक्षर से मेल खाता है , लेकिन यह public static <T extends Class2> void mandatory(T o)विधि हस्ताक्षर से मेल नहीं खाता क्योंकि Yयह विस्तार नहीं करता है Class2

तो विधि mandatory(getClass1())कहता public static <T> void mandatory(T o)है।

इसके विपरीत getInterface1(), आप विधि हस्ताक्षर से getClass1()मेल खाने वाले परिणाम को वापस करने के लिए स्पष्ट रूप से टाइप पैरामीटर निर्दिष्ट नहीं कर सकते public static <T extends Class2> void mandatory(T o):

                       java: interface expected here
                                     
public static <T extends Class1 & C̲l̲a̲s̲s̲2> void helper() {
    mandatory(Test.<T>getClass1());
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.