जब हम पहले से ही अमूर्त वर्ग थे तब जावा 8 में डिफ़ॉल्ट और स्थिर तरीके क्यों जोड़े गए थे?


99

जावा 8 में, इंटरफेस में लागू किए गए तरीके, स्थिर तरीके और तथाकथित "डिफ़ॉल्ट" विधियां हो सकती हैं (जो कि कार्यान्वयन कक्षाओं को ओवरराइड करने की आवश्यकता नहीं है)।

मेरे (शायद भोले) दृश्य में, इस तरह इंटरफेस का उल्लंघन करने की कोई आवश्यकता नहीं थी। इंटरफेस हमेशा एक अनुबंध होता है जिसे आपको पूरा करना चाहिए, और यह एक बहुत ही सरल और शुद्ध अवधारणा है। अब यह कई चीजों का मिश्रण है। मेरी राय में:

  1. स्थिर विधियाँ इंटरफेस से संबंधित नहीं हैं। वे उपयोगिता वर्गों से संबंधित हैं।
  2. "डिफ़ॉल्ट" विधियों को इंटरफेस में बिल्कुल भी अनुमति नहीं दी जानी चाहिए। आप हमेशा इस उद्देश्य के लिए एक अमूर्त वर्ग का उपयोग कर सकते हैं।

संक्षेप में:

जावा 8 से पहले:

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

जावा 8 के बाद:

  • वस्तुतः एक इंटरफ़ेस और एक अमूर्त वर्ग (एकाधिक विरासत के अलावा) के बीच कोई अंतर नहीं है। वास्तव में आप इंटरफ़ेस के साथ एक नियमित वर्ग का अनुकरण कर सकते हैं।
  • कार्यान्वयन की प्रोग्रामिंग करते समय, प्रोग्रामर डिफ़ॉल्ट विधियों को ओवरराइड करना भूल सकते हैं।
  • यदि एक वर्ग एक ही हस्ताक्षर के साथ एक डिफ़ॉल्ट विधि वाले दो या अधिक इंटरफेस को लागू करने का प्रयास करता है तो एक संकलन त्रुटि होती है।
  • एक इंटरफ़ेस में एक डिफ़ॉल्ट विधि जोड़कर, प्रत्येक कार्यान्वयन वर्ग स्वचालित रूप से इस व्यवहार को इनहेरिट करता है। हो सकता है कि इनमें से कुछ कक्षाएं उस नई कार्यक्षमता को ध्यान में रखकर नहीं बनाई गई हों, और यह समस्याएँ पैदा कर सकती हैं। उदाहरण के लिए, यदि कोई default void foo()इंटरफ़ेस में एक नई डिफ़ॉल्ट विधि जोड़ता है Ix, तो उसी हस्ताक्षर के साथ निजी पद्धति को Cxलागू करने Ixऔर रखने वाला वर्ग fooसंकलित नहीं करता है।

इस तरह के बड़े बदलावों के मुख्य कारण क्या हैं और वे क्या नए लाभ (यदि कोई हैं) जोड़ते हैं?


30
बोनस प्रश्न: उन्होंने इसके बजाय कक्षाओं के लिए कई विरासत का परिचय क्यों नहीं दिया?

2
स्थिर विधियाँ इंटरफेस से संबंधित नहीं हैं। वे उपयोगिता वर्गों से संबंधित हैं। नहीं वे @Deprecatedश्रेणी में हैं! अज्ञानता और आलस्य के कारण स्थैतिक विधियाँ जावा में सबसे अधिक दुरुपयोग की जाने वाली रचनाओं में से एक हैं। स्थैतिक तरीकों के बहुत से आमतौर पर अक्षम प्रोग्रामर का अर्थ है, परिमाण के कई आदेशों द्वारा युग्मन में वृद्धि और यूनिट टेस्ट और रिफ्लेक्टर के लिए एक बुरा सपना है जब आपको पता चलता है कि वे एक बुरा विचार क्यों हैं!

11
@JarrodRoberson क्या आप कुछ और संकेत प्रदान कर सकते हैं (लिंक बहुत अच्छे होंगे) "के बारे में एक बुरा सपना है यूनिट टेस्ट और रिफ्लेक्टर जब आपको पता चलता है कि वे एक बुरा विचार क्यों हैं?"। मैंने कभी नहीं सोचा था कि मैं इसके बारे में अधिक जानना चाहूंगा।
पानी में

11
@ क्रिस राज्य की कई विरासत में समस्याओं का एक समूह है, विशेष रूप से स्मृति आवंटन ( क्लासिक हीरे की समस्या ) के साथ। व्यवहार का एक से अधिक वंशानुक्रम, हालांकि, केवल इंटरफ़ेस द्वारा निर्धारित अनुबंध के कार्यान्वयन की बैठक पर निर्भर करता है (इंटरफ़ेस अन्य तरीकों को कॉल कर सकता है जो इसे घोषित करता है और आवश्यकता होती है)। एक सूक्ष्म, लेकिन बहुत दिलचस्प, भेद।
एसएसबी

1
आप मौजूदा इंटरफ़ेस में विधि जोड़ना चाहते हैं, java8 से पहले बोझिल या लगभग संभव नहीं था अब आप इसे केवल डिफ़ॉल्ट विधि के रूप में जोड़ सकते हैं।
VdeX

जवाबों:


59

डिफ़ॉल्ट विधियों के लिए एक अच्छा प्रेरक उदाहरण जावा मानक पुस्तकालय में है, जहां अब आपके पास है

list.sort(ordering);

के बजाय

Collections.sort(list, ordering);

मुझे नहीं लगता कि वे ऐसा कर सकते थे, अन्यथा एक से अधिक कार्यान्वयन के बिना List.sort


19
C # एक्सटेंशन मेथड्स के साथ इस समस्या को खत्म करता है।
रॉबर्ट हार्वे

5
और यह एक लिंक की गई सूची को O (1) अतिरिक्त स्थान और O (n लॉग एन) टाइम मर्जॉर्ट्स का उपयोग करने की अनुमति देता है, क्योंकि लिंक की गई सूचियों को जगह में विलय किया जा सकता है, जावा 7 में यह एक बाहरी सरणी के लिए डंप करता है और फिर उस तरह का
शाफ़्ट क्रेक

5
मुझे यह पेपर मिला है जहां गोएट्ज समस्या बताते हैं। तो मैं इस जवाब को अभी के समाधान के रूप में चिह्नित करूंगा।
मिस्टर स्मिथ

1
@RobertHarvey: दो सौ-मिलियन-आइटम सूची बनाएं <बाइट>, IEnumerable<Byte>.Appendउनसे जुड़ने के लिए उपयोग करें, और फिर कॉल करें Count, फिर मुझे बताएं कि समस्या को कैसे हल करें। यदि CountIsKnownऔर के Countसदस्य थे IEnumerable<T>, तो घटक Appendविज्ञापन CountIsKnownसंग्रह से वापसी कर सकते हैं , लेकिन ऐसे तरीकों के बिना यह संभव नहीं है।
सुपरकैट

6
@ सुपरकैट: मुझे इस बात का जरा भी अंदाजा नहीं है कि आप किस बारे में बात कर रहे हैं।
रॉबर्ट हार्वे

48

सही उत्तर वास्तव में जावा प्रलेखन में पाया जाता है , जो बताता है:

[d] efault विधियाँ आपको अपने पुस्तकालयों के इंटरफेस में नई कार्यक्षमता जोड़ने और उन इंटरफेस के पुराने संस्करणों के लिए लिखे गए कोड के साथ द्विआधारी संगतता सुनिश्चित करने में सक्षम बनाती हैं।

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

इंटरफेस में स्थैतिक तरीकों को अनुमति देने का कारण फिर से प्रलेखन द्वारा प्रकट किया गया है: [t] उसका आपके पुस्तकालयों में सहायक तरीकों को व्यवस्थित करना आपके लिए आसान बनाता है; आप एक अलग वर्ग के बजाय एक ही इंटरफ़ेस के लिए विशिष्ट विधियों को स्थिर रख सकते हैं। दूसरे शब्दों में, स्थिर उपयोगिता वर्ग जैसे कि java.util.Collectionsअब (अंत में) एक विरोधी पैटर्न माना जा सकता है, सामान्य तौर पर ( हमेशा नहीं )। मेरा अनुमान है कि वर्चुअल एक्सटेंशन के तरीकों को लागू करने के बाद इस व्यवहार के लिए समर्थन जोड़ना तुच्छ हो गया था, अन्यथा यह शायद नहीं होता।

इसी तरह की एक टिप्पणी पर, कैसे इन नई सुविधाओं लाभकारी हो सकते हैं का एक उदाहरण, एक वर्ग है कि हाल ही में मुझसे नाराज है पर विचार करना है java.util.UUID। यह वास्तव में UUID प्रकार 1, 2 या 5 के लिए समर्थन प्रदान नहीं करता है , और ऐसा करने के लिए इसे आसानी से संशोधित नहीं किया जा सकता है। यह एक पूर्व-परिभाषित यादृच्छिक जनरेटर के साथ भी फंस गया है जिसे ओवरराइड नहीं किया जा सकता है। असमर्थित यूयूआईडी प्रकारों के लिए कोड को लागू करने के लिए इंटरफ़ेस के बजाय तीसरे पक्ष के एपीआई पर प्रत्यक्ष निर्भरता की आवश्यकता होती है, या फिर रूपांतरण कोड के रखरखाव और इसके साथ जाने के लिए अतिरिक्त कचरा संग्रह की लागत। स्थिर तरीकों के साथ, UUIDइसके बजाय एक इंटरफ़ेस के रूप में परिभाषित किया जा सकता है, जिससे लापता टुकड़ों के वास्तविक तीसरे पक्ष के कार्यान्वयन की अनुमति मिलती है। (यदि UUIDमूल रूप से एक इंटरफ़ेस के रूप में परिभाषित किया गया था, तो हम संभवतः किसी प्रकार के क्लंकी होंगेUuidUtil स्थिर तरीकों के साथ वर्ग, जो बहुत भयानक भी होगा।) जावा के कोर एपीआई के बहुत सारे इंटरफेस पर खुद को आधार बनाने में विफल रहे हैं, लेकिन जावा 8 के रूप में इस बुरे व्यवहार के लिए बहाने की संख्या शुक्र से कम हो गई है।

यह कहना सही नहीं है कि यहाँ [t] एक इंटरफ़ेस और एक अमूर्त वर्ग के बीच कोई अंतर नहीं है , क्योंकि अमूर्त वर्गों में राज्य हो सकता है (अर्थात, खेतों की घोषणा) जबकि इंटरफेस नहीं कर सकते। इसलिए यह कई विरासत या मिक्सिन-शैली विरासत के बराबर नहीं है। उचित मिश्रण (जैसे कि ग्रूवी 2.3 के लक्षण ) की राज्य तक पहुंच है। (ग्रूवी स्टैटिक एक्सटेंशन के तरीकों का भी समर्थन करता है।)

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


1
मेरे अंतिम पैराग्राफ पर आगे अनुवर्ती कार्रवाई के लिए (यानी इंटरफेस में अनुबंध लागू नहीं करते हैं ), यह इंगित करने योग्य है कि defaultविधियां ओवरराइड नहीं कर सकती हैं equals, hashCodeऔर toString। यह क्यों अस्वीकृत है इसकी एक बहुत जानकारीपूर्ण लागत / लाभ विश्लेषण यहाँ पाया जा सकता है: mail.openjdk.java.net/pipermail/lambda-dev/2013-March/…
ngreen

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

वैसे, Java सॉर्ट में तुलनित्र और तुलनीय इंटरफेस के साथ वर्कअराउंड है। लेकिन वे बदसूरत हैं, मुझे लगता है।
एनक्रीन

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

ओह हाँ, मुझे तुलनाकर्ताओं का दर्द मिलता है। मैं एक पेड़ की संरचना पर काम कर रहा हूं, जो सरल होना चाहिए, लेकिन ऐसा नहीं है क्योंकि यह तुलनित्र को सही पाने के लिए बहुत कठिन है। मैं शायद एक कस्टम ट्री क्लास लिखने जा रहा हूँ ताकि समस्या दूर हो सके।
3

44

क्योंकि आपको केवल एक वर्ग विरासत में मिल सकता है। यदि आपको दो इंटरफेस मिले हैं, जिनके कार्यान्वयन पर्याप्त जटिल हैं, तो आपको एक सार आधार वर्ग की आवश्यकता होती है, वे दो इंटरफेस व्यावहारिक रूप से अनन्य हैं।

विकल्प उन अमूर्त आधार वर्गों को स्थिर तरीकों के संग्रह में परिवर्तित करना है और सभी क्षेत्रों को तर्कों में बदलना है। यह इंटरफ़ेस के किसी भी कार्यान्वयनकर्ता को स्थिर विधियों को कॉल करने और कार्यक्षमता प्राप्त करने की अनुमति देगा, लेकिन यह एक ऐसी भाषा में बहुत अधिक बॉयलरप्लेट है जो पहले से ही बहुत अधिक वर्बोज़ है।


इंटरफेस में कार्यान्वयन प्रदान करने में सक्षम होने के लिए एक प्रेरक उदाहरण उपयोगी हो सकता है, इस स्टैक इंटरफ़ेस पर विचार करें:

public interface Stack<T> {
    boolean isEmpty();

    T pop() throws EmptyException;
 }

यह गारंटी देने का कोई तरीका नहीं है कि जब कोई इंटरफ़ेस को लागू करता है, popतो एक अपवाद फेंक देगा यदि स्टैक खाली है। हम इस नियम popको दो विधियों में विभाजित करके लागू कर सकते हैं : एक public finalविधि जो अनुबंध को लागू करती है और एक protected abstractविधि जो वास्तविक पॉपिंग को निष्पादित करती है।

public abstract class Stack<T> {
    public abstract boolean isEmpty();

    protected abstract T pop_implementation();

    public final T pop() throws EmptyException {
        if (isEmpty()) {
            throw new EmptyException();
        else {
            return pop_implementation();
        }
    }
 }

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

मुझे यकीन नहीं है कि इंटरफेस में तरीकों को जोड़ने के लिए जावा 8 का दृष्टिकोण अंतिम तरीकों या संरक्षित अमूर्त विधियों को जोड़ने की अनुमति देता है, लेकिन मुझे पता है कि डी भाषा इसे अनुमति देती है और अनुबंध द्वारा डिजाइन के लिए मूल समर्थन प्रदान करती है । इस तकनीक में कोई खतरा नहीं है क्योंकि popयह अंतिम है, इसलिए कोई भी कार्यान्वयन वर्ग इसे ओवरराइड नहीं कर सकता है।

ओवरराइड करने योग्य तरीकों के डिफ़ॉल्ट कार्यान्वयन के लिए, मैं जावा एपीआई में जोड़े गए किसी भी डिफ़ॉल्ट कार्यान्वयन को केवल उस इंटरफ़ेस के अनुबंध पर निर्भर करता हूं, जो उन्हें जोड़ा गया था, इसलिए इंटरफ़ेस को सही तरीके से लागू करने वाला कोई भी वर्ग डिफ़ॉल्ट कार्यान्वयन के साथ सही व्यवहार करेगा।

इसके अलावा,

वस्तुतः एक इंटरफ़ेस और एक अमूर्त वर्ग (एकाधिक विरासत के अलावा) के बीच कोई अंतर नहीं है। वास्तव में आप इंटरफ़ेस के साथ एक नियमित वर्ग का अनुकरण कर सकते हैं।

यह बिल्कुल सही नहीं है क्योंकि आप किसी इंटरफ़ेस में फ़ील्ड घोषित नहीं कर सकते। कोई भी विधि जिसे आप इंटरफ़ेस में लिखते हैं, किसी भी कार्यान्वयन विवरण पर भरोसा नहीं कर सकता है।


इंटरफेस में स्थिर तरीकों के पक्ष में एक उदाहरण के रूप में, जावा एपीआई में संग्रह जैसे उपयोगिता वर्गों पर विचार करें । वह वर्ग केवल इसलिए मौजूद है क्योंकि उन स्थिर तरीकों को उनके संबंधित इंटरफेस में घोषित नहीं किया जा सकता है। इंटरफ़ेस Collections.unmodifiableListमें बस घोषित किया जा सकता था List, और इसे खोजना आसान था।


4
प्रतिवाद: चूंकि स्थैतिक विधियाँ, यदि ठीक से लिखी गई हैं, तो वे आत्म-निहित हैं, वे एक अलग स्थिर वर्ग में अधिक अर्थ रखते हैं जहाँ उन्हें एकत्र किया जा सकता है और श्रेणी नाम से वर्गीकृत किया जा सकता है, और एक इंटरफ़ेस में कम अर्थ, जहाँ वे अनिवार्य रूप से एक सुविधा है जो वस्तु में स्थिर अवस्था को धारण करने या साइड इफेक्ट का कारण बनने जैसी गालियों को आमंत्रित करता है, जिससे स्थैतिक विधियां अप्राप्य हो जाती हैं।
रॉबर्ट हार्वे

3
@RobertHarvey अगर आपकी स्थिर पद्धति एक वर्ग में है, तो आपको उतनी ही मूर्खतापूर्ण चीजें करने से रोकना होगा? इसके अलावा, इंटरफ़ेस में विधि को किसी भी राज्य की आवश्यकता नहीं हो सकती है। आप बस एक अनुबंध को लागू करने की कोशिश कर सकते हैं। मान लीजिए कि आपको एक Stackइंटरफ़ेस मिला है और आप यह सुनिश्चित करना चाहते हैं कि जब popखाली स्टैक के साथ बुलाया जाए, तो एक अपवाद फेंक दिया जाए। सार तरीकों को देखते हुए boolean isEmpty()और protected T pop_impl(), आप को लागू कर सकता है final T pop() { isEmpty()) throw PopException(); else return pop_impl(); }यह सभी कार्यान्वयन करने वालों पर अनुबंध लागू करता है।
डोभाल

रुको क्या? स्टैक पर पुश और पॉप विधियाँ नहीं होने जा रही हैं static
रॉबर्ट हार्वे

@RobertHarvey मैं स्पष्ट होता यदि टिप्पणियों पर वर्ण सीमा के लिए नहीं, लेकिन मैं एक इंटरफ़ेस में डिफ़ॉल्ट कार्यान्वयन के लिए मामला बना रहा था, न कि स्थैतिक तरीकों से।
डोभाल

8
मुझे लगता है कि डिफ़ॉल्ट इंटरफ़ेस विधियां एक हैक है जो कि मौजूदा कोड को इसके आधार पर अनुकूलित करने की आवश्यकता के बिना मानक पुस्तकालय का विस्तार करने में सक्षम होने के लिए पेश की गई है।
जियोर्जियो

2

शायद इरादा एक निर्भरता के माध्यम से स्थिर जानकारी या कार्यक्षमता को इंजेक्ट करने की आवश्यकता को प्रतिस्थापित करके मिक्सिन कक्षाएं बनाने की क्षमता प्रदान करना था ।

यह विचार इस बात से संबंधित है कि आप इंटरफेस में कार्यान्वित कार्यक्षमता को जोड़ने के लिए C # में एक्सटेंशन विधियों का उपयोग कैसे कर सकते हैं।


1
विस्तार विधियाँ इंटरफेस में कार्यक्षमता नहीं जोड़ती हैं। एक्सटेंशन के तरीके सुविधाजनक list.sort(ordering);रूप का उपयोग करके एक वर्ग पर स्थिर तरीकों को कॉल करने के लिए सिंटैक्टिक चीनी हैं ।
रॉबर्ट हार्वे

यदि आप IEnumerableC # में इंटरफ़ेस को देखते हैं, तो आप देख सकते हैं कि उस इंटरफ़ेस के विस्तार तरीकों को कैसे लागू किया जाता है (जैसे LINQ to Objectsकरता है) हर वर्ग के लिए कार्यक्षमता जोड़ता है जो नकल करता है IEnumerable। यही मैं कार्यक्षमता जोड़कर मतलब है।
rae1

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

2
वास्तव में, और यही कारण है कि मुझे जावा में एक इंटरफ़ेस में स्थिर या डिफ़ॉल्ट तरीके होने पर कुछ संबंध दिखाई देते हैं; कार्यान्वयन उस इंटरफ़ेस पर उपलब्ध है जो क्लास के लिए ही नहीं इंटरफ़ेस के लिए उपलब्ध है।
rae1

1

दो मुख्य उद्देश्य जो मैं defaultविधियों में देखता हूं (कुछ उपयोग के मामले दोनों उद्देश्यों की सेवा करते हैं):

  1. सिंटेक्स शुगर। एक उपयोगिता वर्ग उस उद्देश्य की पूर्ति कर सकता है, लेकिन उदाहरण के तरीके अच्छे हैं।
  2. मौजूदा इंटरफ़ेस का विस्तार। कार्यान्वयन सामान्य है लेकिन कभी-कभी अक्षम है।

अगर यह सिर्फ दूसरे उद्देश्य के बारे में था, तो आप इसे बिल्कुल नए इंटरफ़ेस की तरह नहीं देखेंगे Predicate। सभी @FunctionalInterfaceएनोटेट इंटरफेस के लिए एक सार विधि की आवश्यकता होती है ताकि एक लैम्बडा इसे लागू कर सके। जोड़ी defaultकी तरह तरीकों and, or, negateबस उपयोगिता कर रहे हैं, और आप उन्हें ओवरराइड करने के लिए नहीं जा सकते। हालांकि, कभी-कभी स्थिर तरीके बेहतर होते हैं

मौजूदा इंटरफेस के विस्तार के लिए - यहाँ तक कि, कुछ नए तरीके सिंटेक्स चीनी हैं। Collectionजैसे stream, के तरीके forEach, removeIf- मूल रूप से, यह सिर्फ उपयोगिता है जिसे आपको ओवरराइड करने की आवश्यकता नहीं है। और फिर जैसे तरीके हैं spliterator। डिफ़ॉल्ट कार्यान्वयन सबॉप्टिमल है, लेकिन हे, कम से कम कोड संकलित करता है। यदि आपका इंटरफ़ेस पहले से ही प्रकाशित है और व्यापक रूप से उपयोग किया जाता है, तो केवल इसका सहारा लें।


के रूप में staticतरीकों, मुझे लगता है कि दूसरों को काफी अच्छी तरह से इसे कवर: यह इंटरफ़ेस का अपना उपयोगिता वर्ग होने के लिए अनुमति देता है। शायद हम Collectionsजावा के भविष्य से छुटकारा पा सकते हैं? Set.empty()रॉक होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.