2014-10-23 9 views
6

मैं जब मैंने देखा है कि निम्नलिखित कोड चेतावनी के बिना संकलित बहुत हैरान था और प्रिंट Integer/String:एक सामान्य विधि कैसे लिखें जो जावा में उसी प्रकार के दो तर्क लेता है?

public final class GenericsTest { 
    private static <T> void method(T arg1, T arg2) { 
     System.out.println(arg1.getClass().getSimpleName()); 
     System.out.println(arg2.getClass().getSimpleName()); 
    } 

    public static void main(String[] args) { 
     method(1, "1"); 
    } 
} 

मैं एक संकलन त्रुटि की उम्मीद।

क्या कोई कारण है कि यह कोड संकलित करता है?

यह सुनिश्चित करने का सही तरीका क्या है कि तर्कों का एक ही प्रकार है?

संपादित करें: बाध्य प्रकार पैरामीटर के बारे में क्या?

private static <T, U extends T> void method(T arg1, U arg2) { 
    System.out.println(arg1.getClass().getSimpleName()); 
    System.out.println(arg2.getClass().getSimpleName()); 
} 

दुर्भाग्य से, जावा चक्रीय बाधाओं अनुमति नहीं देता: सबसे अच्छा मैं के बारे में सोच सकते हैं कि यह है। <T extends U, U extends T> संकलित नहीं करता है। क्या यह एक मृत अंत है?

+0

विधि को कॉल करते समय आप सामान्य प्रकार बता सकते हैं: 'जेनिक्सटेस्ट। विधि (1, "1"); // संकलित नहीं करेगा ' – August

उत्तर

6

कारण यह है कि इस संकलित, ObjectSerializable & Comparable<? extends Serializable & Comparable<? extends Comparable<?>>> के बाद 1Integer को बॉक्सिंग जाता है और "1" एक String के रूप में पारित हो जाता है है, क्योंकि जावा, तर्क में पारित के सबसे विशिष्ट महाप्रकार का अनुमान लगा होगा इस मामले में।

जेनरिक बिना

:

private static void method(Number arg1, Number arg2) { 

यहां तक ​​कि जेनरिक के बिना, आप एक Integer और एक Double में पारित कर सकते हैं।

सिर्फ अगर सवाल में प्रकार है final आप ऐसा कर सकते हैं, जेनरिक के बिना:

private static void method(String arg1, String arg2) { 
    // Yes, they're both Strings, guaranteed. 

वहाँ जेनरिक है कि मैं के बारे में सोच सकते हैं सुनिश्चित करें कि वे सही प्रकार हैं के साथ एक बढ़त मामला है। यदि आपके पास final कक्षा है, और आप ऊपरी बाउंड रखते हैं, तो आप इसे उसी कक्षा में प्रतिबंधित कर सकते हैं।

public <T extends MyFinalClass> void method(T arg1, T arg2) { 
    // Yes, they're both MyFinalClasses 
} 

लेकिन फिर आप जेनरिक के बिना वही काम कर सकते थे।

public void method(MyFinalClass arg1, MyFinalClass arg2) { 
    // Yes, they're both MyFinalClasses 
} 
+0

जावा वास्तव में सुपरटेप' Serializable और तुलनात्मक < Serializable और तुलनात्मक विस्तार करता है >> 'बढ़ाता है। – August

1

ऐसा करना संभव नहीं है। या इसे किसी अन्य तरीके से देखने के लिए, दो संदर्भ तर्क हमेशा "एक ही प्रकार" होते हैं - Object - संदर्भ प्रकार के किसी भी तर्क हमेशा Object के उदाहरण होते हैं।

T हमेशा Object हो सकता है, और कोई भी दो संदर्भ तर्क ले सकते हैं। <T, U extends T> void method(T arg1, U arg2) के साथ भी, T और U दोनों Object हो सकते हैं, और इस प्रकार फिर से दो तर्क ले सकते हैं।

इस के लिए अंतर्निहित कारण इस तरह की कोई समस्या है करने के लिए कोई प्रकार-सुरक्षा कारण नहीं है कि है। विरासत के प्रमुख बिंदुओं में से एक यह है कि सुपरक्लास उदाहरणों को सुरक्षित रूप से उपclass उदाहरणों का इलाज करना संभव होना चाहिए। सुपरक्लास प्रकार का संदर्भ प्रकार उस वर्ग या उप-वर्ग के उदाहरण को इंगित कर सकता है। इसलिए, दो संदर्भ चर एक ही संकलन समय प्रकार है कि, हमेशा अलग उपवर्ग प्रकार के उदाहरण के लिए रनटाइम पर इंगित कर सकते हैं, पूरी तरह से सुरक्षित रूप से।तो आप कभी संकलन समय पर, दो उदाहरणों के वास्तविक रनटाइम कक्षाओं के संबंधों के बारे में कोई बयान नहीं दे सकते हैं, इसके अलावा वे संकलन-समय प्रकार के उप-वर्ग हैं। चूंकि यह दो तर्कों के लिए रनटाइम पर विभिन्न वर्गों के उदाहरणों के लिए सुरक्षित है, इसलिए वास्तव में विभिन्न संकलन-समय प्रकारों के दो तर्कों को पारित करने के लिए यह कम सुरक्षित नहीं हो सकता है।

3

आप कक्षा को अतिरिक्त पैरामीटर के रूप में जोड़ सकते हैं।

private static <T> void method(T arg1, T arg2, Class<T> type) { 
    // ... 
} 

अब आपको सामान्य प्रकार निर्दिष्ट करना होगा।

आप अभी भी method(1, "1", Object.class); पर कॉल कर सकते हैं लेकिन कम से कम आप सामान्य प्रकार के बारे में स्पष्ट हैं।

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