दिलचस्प पोस्ट
जावा में एक यूआरएल या यूआरआर बनाने के लिए मुहावरेदार तरीका क्या है? कैसे एक x264 सी एपीआई का उपयोग कर H264 में छवियों की श्रृंखला को एक सांकेतिक शब्दों में बदलना है? पायथन में मेटाक्लास क्या है? मैक पर IntelliJ IDEA में IDE स्मृति सीमा को कैसे बढ़ाएं? एंड्रॉइड में सभी कैमरा छवियों को सूचीबद्ध करें स्मृति में कितने स्ट्रिंग ऑब्जेक्ट बनाए जाएंगे? हायफनेटेड नाम के साथ मैं इस ऑब्जेक्ट प्रॉपर्टी का उपयोग कैसे करूं? सर्वर पर पोस्ट करने के लिए NSURLRequest का उपयोग करने में समस्या गैर यादृच्छिक हैश कार्यों के कारण आवेदन भेद्यता प्रारंभिक सूची दृश्य स्टूडियो 2012 में वेक्टर के साथ काम नहीं कर रही है? क्या जीपीएस इंटरनेट की ज़रूरत है? UITextField की प्रारंभिक कुंजीपटल एनीमेशन पर सुपर धीमा अंतराल / देरी शीर्ष पर से एंड्रॉइड स्लाइडिंग ड्रॉवर? मोनोडायड: कस्टम दृश्य के कन्स्ट्रक्टर को बुलाते समय त्रुटि – दोदासक्रोल दृश्य विम में एक अधिक उपयोगी स्थिति?

पैरामीटर के वास्तविक प्रकार के आधार पर अधिभारित विधि चयन

मैं इस कोड के साथ प्रयोग कर रहा हूं:

interface Callee { public void foo(Object o); public void foo(String s); public void foo(Integer i); } class CalleeImpl implements Callee public void foo(Object o) { logger.debug("foo(Object o)"); } public void foo(String s) { logger.debug("foo(\"" + s + "\")"); } public void foo(Integer i) { logger.debug("foo(" + i + ")"); } } Callee callee = new CalleeImpl(); Object i = new Integer(12); Object s = "foobar"; Object o = new Object(); callee.foo(i); callee.foo(s); callee.foo(o); 

यह foo(Object o) तीन बार प्रिंट करता है मुझे उम्मीद है कि विधि चयन को वास्तविक (घोषित नहीं) पैरामीटर प्रकार को ध्यान में रखना चाहिए। क्या मैं कुछ भूल रहा हूँ? क्या इस कोड को संशोधित करने का एक तरीका है, ताकि वह foo(12) , foo("foobar") और foo(Object o) प्रिंट foo(12) ?

वेब के समाधान से एकत्रित समाधान "पैरामीटर के वास्तविक प्रकार के आधार पर अधिभारित विधि चयन"

मुझे उम्मीद है कि विधि चयन को वास्तविक (घोषित नहीं) पैरामीटर प्रकार को ध्यान में रखना चाहिए। क्या मैं कुछ भूल रहा हूँ?

हाँ। आपकी अपेक्षा गलत है जावा में, गतिशील पद्धति प्रेषण केवल उस ऑब्जेक्ट के लिए होता है जिस पर विधि बुलाया जाता है, अतिभारित तरीकों के पैरामीटर प्रकारों के लिए नहीं।

जावा भाषा विशिष्टता का हवाला देते हुए:

जब कोई विधि लागू की जाती है (§15.12), तो वास्तविक तर्कों (और किसी भी स्पष्ट प्रकार तर्क) की संख्या और तर्कों के संकलन-समय के प्रकार का उपयोग किया जाता है, समय के संकलन पर, उस विधि के हस्ताक्षर को निर्धारित करने के लिए जिसे §15.12.2)। यदि विधि जिसे लागू किया जाना है एक उदाहरण विधि है, तो वास्तविक विधि को चलाने के लिए निर्धारित समय पर निर्धारित किया जाएगा, गतिशील विधि देखने का उपयोग (§15.12.4)।

जैसा कि ओवरलोडिंग से पहले बताया गया है संकल्प समय संकलन पर किया जाता है।

जावा पझलरों के लिए एक अच्छा उदाहरण है:

पहेली 46: भ्रामक निर्माता का मामला

यह पहेली आपको दो भ्रामक कन्स्ट्रक्टर के साथ प्रस्तुत करती है। मुख्य विधि एक निर्माता का आह्वान करता है, लेकिन कौन सा एक? कार्यक्रम का उत्पादन उत्तर पर निर्भर करता है। कार्यक्रम क्या प्रिंट करता है, या यह कानूनी भी है?

 public class Confusing { private Confusing(Object o) { System.out.println("Object"); } private Confusing(double[] dArray) { System.out.println("double array"); } public static void main(String[] args) { new Confusing(null); } } 

समाधान 46: भ्रामक निर्माता का मामला

… जावा की अधिभार संकल्प प्रक्रिया दो चरणों में चलती है। पहला चरण सभी तरीकों या कन्स्ट्रक्टरों का चयन करता है जो पहुंच योग्य और लागू होते हैं। दूसरे चरण में पहले चरण में चयनित सबसे विशिष्ट विधियों या कंसल्टेंट्स का चयन किया गया है। एक विधि या कन्स्ट्रक्टर दूसरे से कम विशिष्ट है , अगर वह अन्य [जेएलएस 15.12.2.5] को पारित किए गए किसी भी पैरामीटर को स्वीकार कर सकता है।

हमारे कार्यक्रम में, दोनों कन्स्ट्रक्टर पहुंच योग्य और लागू होते हैं। कन्स्ट्रक्टर भ्रामक (ऑब्जेक्ट) भ्रमित करने के लिए पारित किसी भी पैरामीटर स्वीकार करता है (डबल []) , इसलिए भ्रमित (ऑब्जेक्ट) कम विशिष्ट है (प्रत्येक डबल सरणी एक ऑब्जेक्ट है , लेकिन हर ऑब्जेक्ट एक डबल ऐरे नहीं है ।) सबसे विशिष्ट कन्स्ट्रक्टर इसलिए भ्रामक (डबल []) है , जो प्रोग्राम के आउटपुट को बताता है।

यह व्यवहार समझ में आता है यदि आप टाइप डबल का एक मूल्य दोहराएं [] ; यदि आप नल से गुजरते हैं तो यह प्रतिद्वंद्वी है। इस पहेली को समझने की चाबी यह है कि जिस पद्धति या निर्माता का परीक्षण सबसे विशिष्ट है वह वास्तविक पैरामीटर का उपयोग नहीं करता है : इनवोकेशन में दिखने वाले पैरामीटर। उनका उपयोग केवल यह निर्धारित करने के लिए किया जाता है कि कौन से ओवरलोडिंग लागू हों। एक बार कंपाइलर यह निर्धारित करता है कि कौन सा ओवरलोडिंग लागू और पहुंच योग्य है, यह केवल औपचारिक मापदंडों का उपयोग करते हुए, सबसे अधिक विशिष्ट ओवरलोडिंग का चयन करता है: घोषणा में दिखने वाले पैरामीटर

भ्रामक (ऑब्जेक्ट) कन्स्ट्रक्टर को एक अशक्त पैरामीटर के साथ लाने के लिए, नया भ्रामक ((ऑब्जेक्ट) रिक्त लिखें। यह सुनिश्चित करता है कि केवल भ्रामक (ऑब्जेक्ट) लागू है। अधिक सामान्यतः, एक विशिष्ट ओवरलोडिंग का चयन करने के लिए संकलक को मजबूर करने के लिए, औपचारिक मापदंडों के घोषित प्रकारों के लिए वास्तविक पैरामीटर डालें।

तर्कों के प्रकारों के आधार पर किसी विधि को कॉल भेजने की क्षमता को एकाधिक प्रेषण कहा जाता है। जावा में यह विज़िटर पैटर्न के साथ किया जाता है

हालांकि, चूंकि आप Integer s और String एस के साथ काम कर रहे हैं, आप आसानी से इस पैटर्न को शामिल नहीं कर सकते (आप इन वर्गों को संशोधित नहीं कर सकते हैं)। इस प्रकार, वस्तु रन-टाइम पर एक विशाल switch विकल्प का अपना हथियार होगा।

जावा में कॉल करने के लिए विधि (जैसा कि उपयोग करने के लिए विधि हस्ताक्षर) समय संकलन पर निर्धारित होता है, इसलिए यह संकलन समय प्रकार के साथ चला जाता है।

इस के आस-पास काम करने के लिए विशिष्ट पैटर्न ऑब्जेक्ट हस्ताक्षर के साथ विधि में ऑब्जेक्ट प्रकार की जांच करना है और कलाकारों के साथ विधि के लिए प्रतिनिधि है।

  public void foo(Object o) { if (o instanceof String) foo((String) o); if (o instanceof Integer) foo((Integer) o); logger.debug("foo(Object o)"); } 

यदि आपके पास कई प्रकार हैं और यह असहनीय है, तो विधि ओवरलोडिंग संभवत: सही दृष्टिकोण नहीं है, बल्कि सार्वजनिक विधि को ऑब्जेक्ट लेना चाहिए और प्रत्येक ऑब्जेक्ट प्रकार को उचित हैंडलिंग का प्रतिनिधित्व करने के लिए किसी प्रकार की रणनीति पद्धति को लागू करना चाहिए।

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

मैंने जो हल इस्तेमाल किया था वह प्रतिबिंब के माध्यम से कन्स्ट्रक्टर को देखना था …

 public Parameter[] convertObjectsToParameters(Object[] objArray) { Parameter[] paramArray = new Parameter[objArray.length]; int i = 0; for (Object obj : objArray) { try { Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass()); paramArray[i++] = cons.newInstance(obj); } catch (Exception e) { throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e); } } return paramArray; } 

कोई बदसूरत उदाहरण, स्विच स्टेटमेंट या आगंतुक पैटर्न की आवश्यकता नहीं है! 🙂

जावा किस विधि को कॉल करने के लिए निर्धारित करने की कोशिश करते समय जावा को संदर्भ प्रकार दिखता है यदि आप अपने कोड को बल देना चाहते हैं तो आप 'सही' विधि चुनते हैं, तो आप अपने खेतों को विशिष्ट प्रकार के उदाहरणों के रूप में घोषित कर सकते हैं:

 Integeri = new Integer(12); String s = "foobar"; Object o = new Object(); 

आप परम के प्रकार के रूप में अपने पैरामीटर भी डाल सकते हैं:

 callee.foo(i); callee.foo((String)s); callee.foo(((Integer)o); 

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