दिलचस्प पोस्ट
एनिमेशन के माध्यम से एक गतिविधि में स्वैप टुकड़ा प्रतिवर्ती हैश समारोह? जावा और सुपरक्लासेस में विरासत (वस्तु, कक्षा) स्क्रॉल करने योग्य जेबेट के साथ एक जेपीनल को प्रिंट करना sizeof का उपयोग किए बिना डेटाैट का आकार एएसपी.एन.टी.नेट सत्र राज्य सेवा का उपयोग करते हुए सभी अनुप्रयोगों में सत्र साझा करना स्ट्रक्चरमैप सिंगलटन उपयोग (एक क्लास दो इंटरफ़ेस को कार्यान्वित करता है) एक हशमॉप की उधार लेते हुए उस गुंजाइश से परे रहता है जो यह है? दोहराव करते समय संशोधित सूची कैसे एक छवि में डीपीआई जानकारी सेट करने के लिए? क्या नेट मैनेजमेंट के लिए मेवेन विकल्प या बंदरगाह है? "ImportError: Google एप इंजन से dev_appserver.py के साथ _ssl नामक कोई मॉड्यूल" नहीं है गिट शाखा पहुंच को प्रतिबंधित करने का एक तरीका है? अगले और पिछले दिन पीएचपी के साथ मिलें डुप्लिकेट HTTP GET क्वेरी कुंजियों की आधिकारिक स्थिति

Java8: java.lang.Object से किसी विधि के लिए डिफ़ॉल्ट विधि को परिभाषित करने के लिए इसे क्यों प्रतिबंधित किया गया है

हमारे जावा टूलबॉक्स में डिफ़ॉल्ट तरीके एक नया उपकरण हैं हालांकि, मैंने एक इंटरफ़ेस लिखने की कोशिश की जो toString विधि का एक default संस्करण परिभाषित करता है। जावा मुझसे कहता है कि यह निषिद्ध है, क्योंकि java.lang.Object में घोषित विधियों default एड नहीं हो सकता है। यह एक केस क्यों है?

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

तो, जावा डिजाइनरों ने Object से तरीकों को अध्यारोपित करने के लिए default तरीकों को अनुमति देने का फैसला क्यों किया?

Solutions Collecting From Web of "Java8: java.lang.Object से किसी विधि के लिए डिफ़ॉल्ट विधि को परिभाषित करने के लिए इसे क्यों प्रतिबंधित किया गया है"

ये अभी तक उन भाषा डिजाइन मुद्दों में से एक है जो "स्पष्ट रूप से एक अच्छा विचार" लगता है जब तक कि आप खुदाई शुरू नहीं करते और आपको लगता है कि वास्तव में यह एक बुरा विचार है।

इस मेल में इस विषय पर बहुत कुछ है (और अन्य विषयों पर भी)। कई डिज़ाइन बलों ने हमें वर्तमान डिजाइन में लाने के लिए एकत्रित किया:

  • विरासत मॉडल को सरल रखने की इच्छा;
  • तथ्य यह है कि एक बार जब आप स्पष्ट उदाहरण (उदाहरण के लिए, एक इंटरफ़ेस में AbstractList को बदलते हुए) देखते हैं, तो आप समझते हैं कि इनहेरिटिंग बराबर / हैशोड / टॉस्ट्रिंग दृढ़ता से एकल उत्तराधिकार और राज्य से बनी हुई है, और इंटरफेस बहुसंख्यक विरासत और स्टेटलेस हैं;
  • कि यह संभवतः कुछ आश्चर्यजनक व्यवहार के लिए दरवाजा खोल दिया है

आप पहले से ही "यह आसान रखें" लक्ष्य पर छुआ है; विरासत और संघर्ष-रिज़ॉल्यूशन के नियम बहुत सरल होने के लिए डिज़ाइन किए गए हैं (कक्षाएं इंटरफेस पर जीतते हैं, सुपर इंटरफेस पर व्युत्पन्न इंटरफेस जीत जाती हैं, और किसी अन्य संघर्ष को लागू करने वाले वर्ग द्वारा हल किया जाता है।) बेशक इन नियमों को एक अपवाद बनाने के लिए छेड़ा जा सकता है, लेकिन मुझे लगता है कि जब आप उस स्ट्रिंग पर खींचने लगेंगे, तो आपको लगता है कि वृद्धिशील जटिलता उतनी जितनी छोटा नहीं जितनी आपको लगता होगा।

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

यह AbstractList उदाहरण को निकालना आसान है; यह सुंदर होगा अगर हम AbstractList से छुटकारा पाएं और व्यवहार को List इंटरफ़ेस में डाल दिया। लेकिन एक बार जब आप इस स्पष्ट उदाहरण से आगे बढ़ते हैं, तो मिल पाए जाने के कई अन्य अच्छे उदाहरण नहीं हैं। जड़ में, AbstractList एकल विरासत के लिए डिज़ाइन किया गया है। लेकिन इंटरफेस कई विरासत के लिए डिज़ाइन किया जाना चाहिए।

इसके अलावा, कल्पना करें कि आप इस वर्ग को लिख रहे हैं:

 class Foo implements com.libraryA.Bar, com.libraryB.Moo { // Implementation of Foo, that does NOT override equals } 

Foo लेखक supertypes को देखता है, बराबर का कोई क्रियान्वयन नहीं देखता है, और निष्कर्ष निकाला है कि संदर्भ समानता प्राप्त करने के लिए, उसे जो ज़रूरत है वह Object बराबर है। उसके बाद, अगले सप्ताह, बार के लिए पुस्तकालय के रखरखाव "मदद से" एक डिफ़ॉल्ट जोड़ता कार्यान्वयन के equals है ओह! अब Foo के शब्दों को एक अन्य रखरखाव डोमेन में एक इंटरफ़ेस द्वारा "उपयोगी ढंग से" एक सामान्य विधि के लिए डिफ़ॉल्ट जोड़ दिया गया है।

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

इसलिए, जब यह एक हानिरहित सुविधा की तरह लगता है, यह वास्तव में बहुत हानिकारक है: यह थोड़ा वृद्धिशील व्यक्तित्व के लिए बहुत जटिलता को जोड़ता है, और इसे अच्छी तरह से अविश्वासी, हानिरहित दिखने वाले परिवर्तनों के लिए अलग-अलग संकलित इंटरफेस को कमजोर करने के लिए बहुत आसान बनाता है कक्षाओं को कार्यान्वित करने का इरादा शब्दों

java.lang.Object में तरीकों के लिए इंटरफेस में डिफ़ॉल्ट विधियों को परिभाषित करने से मना किया जाता है, क्योंकि डिफ़ॉल्ट विधियां "पहुंचने योग्य" नहीं होती हैं

इंटरफ़ेस को कार्यान्वित करने वाले वर्गों में डिफ़ॉल्ट इंटरफ़ेस विधियों को ओवरराइट किया जा सकता है और इस पद्धति का वर्ग कार्यान्वयन इंटरफ़ेस कार्यान्वयन की तुलना में एक उच्च प्राथमिकता है, भले ही पद्धति एक सुपर क्लास में लागू की गई हो। चूंकि सभी कक्षाएं java.lang.Object से java.lang.Object , java.lang.Object में विधियों को इंटरफ़ेस में डिफ़ॉल्ट पद्धति पर प्राथमिकता होती है और इसके बजाय इसे लागू किया जाता है।

ओरेकल से ब्रायन गोएट्ज़ इस मेलिंग सूची पोस्ट में डिजाइन के फैसले पर कुछ और जानकारी प्रदान करता है।

मुझे जावा भाषा के लेखकों के सिर में नहीं देखा गया है, इसलिए हम अनुमान लगा सकते हैं। लेकिन मैं कई कारण देखता हूं और इस मुद्दे पर उनके साथ सहमत हूं।

डिफ़ॉल्ट विधियों को लागू करने का मुख्य कारण पुराने कार्यान्वयन की पिछड़े संगतता को तोड़ने के बिना इंटरफेस के नए तरीकों को जोड़ने में सक्षम होना है। प्रत्येक कार्यान्वयन कक्षाओं में परिभाषित करने के लिए आवश्यकता के बिना "सुविधा" विधियों को प्रदान करने के लिए डिफ़ॉल्ट विधियों का भी उपयोग किया जा सकता है

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

"बेस क्लास हमेशा जीत जाता है" नियम में इसके ठोस कारण भी होते हैं I यह माना जाता है कि कक्षाएं वास्तविक कार्यान्वयन को परिभाषित करती हैं, जबकि इंटरफेस डिफ़ॉल्ट कार्यान्वयन को परिभाषित करते हैं, जो कुछ कमजोर हैं।

इसके अलावा, सामान्य नियमों के किसी भी अपवाद को शुरू करने से अनावश्यक जटिलता का कारण बनता है और अन्य प्रश्न उठाते हैं। ऑब्जेक्ट (अधिक या कम) किसी भी अन्य के रूप में एक वर्ग है, तो यह अलग व्यवहार क्यों होना चाहिए?

और सब कुछ, आपके द्वारा प्रस्तावित समाधान शायद पेशेवरों से अधिक विपक्ष लाएगा

तर्क बहुत आसान है, क्योंकि ऑब्जेक्ट सभी जावा कक्षाओं के लिए आधार वर्ग है। इसलिए यहां तक ​​कि अगर हमारे पास कुछ इंटरफ़ेस में ऑब्जेक्ट की विधि को डिफ़ॉल्ट पद्धति के रूप में परिभाषित किया गया है, तो यह बेकार होगा क्योंकि ऑब्जेक्ट की विधि हमेशा उपयोग की जाएगी यही कारण है कि भ्रम से बचने के लिए, हम डिफ़ॉल्ट पद्धतियां नहीं कर सकते हैं जो ऑब्जेक्ट क्लास विधियों को ओवरराइड कर रहे हैं।

बहुत पश्चातापपूर्ण उत्तर देने के लिए, यह केवल java.lang.Object से सार्वजनिक विधि के लिए एक default विधि को परिभाषित करने के लिए मना किया गया है। विचार करने के लिए 11 तरीके हैं, जिन्हें इस प्रश्न का उत्तर देने के तीन तरीकों से वर्गीकृत किया जा सकता है।

  1. Object विधियों के छह default विधियों नहीं हो सकते हैं क्योंकि वे final और सभी पर ओवरराइड नहीं किया जा सकता है: getClass() , notify() , notify() notifyAll() , wait() , wait(long) , और wait(long, int)
  2. ब्रायन गेट्स द्वारा ऊपर दिए गए कारणों के लिए Object तीन तरीकों में default तरीके नहीं हो सकते हैं: equals(Object) , hashCode() , और toString()
  3. Object विधियों में से दो default तरीके हो सकते हैं, हालांकि इस तरह के डिफॉल्ट का मान संदिग्ध है: clone() और finalize()

     public class Main { public static void main(String... args) { new FOO().clone(); new FOO().finalize(); } interface ClonerFinalizer { default Object clone() {System.out.println("default clone"); return this;} default void finalize() {System.out.println("default finalize");} } static class FOO implements ClonerFinalizer { @Override public Object clone() { return ClonerFinalizer.super.clone(); } @Override public void finalize() { ClonerFinalizer.super.finalize(); } } }