मैं प्रतीत होता है अनुरूप कोड के विभिन्न संकलन परिणामों को समझने की कोशिश कर रहा हूं। ऐसा प्रतीत होता है कि T को T डालना संभव है, लेकिन केवल तभी T एक ठोस वर्ग से बंधे नहीं हैं। इसलिए दिया ...

List<Object> bis = new ArrayList<>();

निम्नलिखित class Test<T> के साथ-साथ class Test<T extends CharSequence> में संकलित हैं, लेकिन class Test<T extends BigDecimal> में नहीं और class Test<T extends BigDecimal & CharSequence> में नहीं।

List<T> result = (List<T>) bis;

तो अंतर T वर्ग प्रकार और इंटरफ़ेस प्रकार के साथ बंधा हुआ कहां से आता है?

संपादित :

कुछ अनुरोध प्रति पूर्ण कोड। यह लाइन 9 में संकलक चेतावनी के साथ संकलित करता है। यह वास्तव में result के आइटमों के संचालन के रूप में असुरक्षित है, जैसे कि वे ClassCastException परिणाम ClassCastException के उदाहरण थे।

    public class Sandbox<T extends CharSequence> {

    public static void main(String[] args) {
        new Sandbox<CharSequence>().foo();
    }

    private void foo() {    
        List<Object> bis = Arrays.asList(Integer.valueOf(1));
        List<T> result = (List<T>) bis;
        System.out.println(result);
    }
}

हालाँकि, यह बिल्कुल संकलन नहीं है:

    public class Sandbox<T extends BigDecimal> {

    public static void main(String[] args) {
        new Sandbox<BigDecimal>().foo();
    }

    private void foo() {    
        List<Object> bis = Arrays.asList(Integer.valueOf(1));
        List<T> result = (List<T>) bis;
        System.out.println(result);
    }

}

9 लाइन में कंपाइलर त्रुटि: List<Object> को List<Object> नहीं डाली जा सकती।

5
gdabski 17 नवम्बर 2015, 01:10

2 जवाब

सबसे बढ़िया उत्तर

खैर यह List<Object> bis = Arrays.asList(Integer.valueOf(1)); स्पष्ट रूप से संकलन नहीं करता है क्योंकि Arrays.asList(Integer.valueOf(1)) List<Integer> वापस आ जाएगा, इसीलिए आपको Cannot cast List<Object> to List<T> मिलेगा।

दूसरा मामला, ग्रहण बेतुका T extends CharSequence के साथ संकलित करता है, लेकिन मैंने एक ऑनलाइन संकलक के साथ जाँच की और यह संकलन नहीं करता है, इसलिए संभवतः यह एक ग्रहण बग है।

0
Ramanlfc 16 नवम्बर 2015, 23:00

इस तरह के व्यवहार को समझने के लिए कुंजी यह समझ रही है कि इरेज़र वास्तव में क्या करता है। लोकप्रिय धारणा के बावजूद कि यह रनटाइम पर प्रकार के मापदंडों को हटा देता है - यह वास्तव में इस तरह से काम नहीं करता है। यह क्या करता है - यह कम करता है उन्हें घोषित पैरामीटर सीमा तक। तो कहीं भी आप List<T> टाइप करते हैं, जहां T की सीमा होती है, यह वास्तव में List<[lower-bound-of-T]> तक कम हो जाती है। और चूंकि Object CharSequence, List<Object> List<T> पर नहीं डाला जा सकता (क्योंकि इसका मतलब कम से कम List<CharSequence>) नहीं है।

ऐसा क्यूँ होता है? कल्पना करें कि आपके Sandbox वर्ग में वह विधि है जो टाइप T के पैरामीटर को स्वीकार करती है:

public class Sandbox<T extends CharSequence> {
    void bar(T param) {
        //...
    }
}

bar(T) स्वीकार कर सकते हैं T 's और T कुछ भी है जो CharSequence का विस्तार करता है, इसलिए मूल रूप से रनटाइम के दौरान यह प्रभावी रूप से काम करता है

 void bar(CharSequence param) {
     //...
 }

और इस प्रकार यह सरल Object स्वीकार नहीं किया जा सकता है। इसीलिए केवल गैर-खाली निचले पैरामीटर से मौजूद है, ...<Object> से मुक्त कलाकारों को प्रतिबंधित करता है

इसके अलावा, वाइल्डकार्ड ? प्रकार का पैरामीटर आपके दिमाग को उड़ा सकता है। यह कहता है कि संकलक कुछ इस तरह है " मुझे नहीं पता कि यह क्या है, लेकिन मुझे पूरा यकीन है कि यह सभी सीमाओं को संतुष्ट करता है।" इस तथ्य सहित बहुत अजीब है, आप इसे (लगभग?) कुछ भी कर सकते हैं, इसलिए यह संभव बनाता है

  List<Object> bis = Arrays.asList(Integer.valueOf(1));
  List<T> result = (List<T>) (List<?>) bis;

इसलिए जब जेनेरिक के साथ डिजाइन वर्ग की बात आती है, तो आपको बहुत, बहुत सावधान रहना चाहिए।

0
Vasily Liaskovsky 17 नवम्बर 2015, 09:41