Abstact वर्ग और इंटरफ़ेस के बीच अंतर
- जावा 8 में सार कक्षाएं बनाम इंटरफेस
- वैचारिक अंतर:
जावा 8 में इंटरफेस डिफॉल्ट मेथड्स
- डिफ़ॉल्ट विधि क्या है?
- डिफ़ॉल्ट विधि का उपयोग कर हल किया गया ForEach विधि संकलन त्रुटि
- डिफ़ॉल्ट विधि और एकाधिक वंशानुक्रम की समस्याएं
- जावा इंटरफ़ेस डिफ़ॉल्ट तरीकों के बारे में महत्वपूर्ण बिंदु:
जावा इंटरफ़ेस स्थैतिक विधि
- जावा इंटरफेस स्टेटिक विधि, कोड उदाहरण, स्थिर विधि बनाम डिफ़ॉल्ट विधि
- जावा इंटरफेस स्थिर विधि के बारे में महत्वपूर्ण बिंदु:
जावा फंक्शनल इंटरफेस
जावा 8 में सार कक्षाएं बनाम इंटरफेस
जावा 8 इंटरफ़ेस परिवर्तनों में स्थिर तरीके और डिफ़ॉल्ट तरीके शामिल हैं। जावा 8 से पहले, हम इंटरफेस में केवल विधि घोषणाएं कर सकते थे। लेकिन जावा 8 से, हम इंटरफेस में डिफ़ॉल्ट तरीके और स्थिर तरीके रख सकते हैं।
डिफ़ॉल्ट विधि की शुरुआत करने के बाद, ऐसा लगता है कि इंटरफेस और अमूर्त वर्ग समान हैं। हालांकि, वे अभी भी जावा 8 में अलग अवधारणा हैं।
सार वर्ग कंस्ट्रक्टर को परिभाषित कर सकता है। वे अधिक संरचित हैं और उनके साथ एक राज्य जुड़ा हो सकता है। जबकि इसके विपरीत, डिफ़ॉल्ट पद्धति को केवल अन्य इंटरफ़ेस विधियों को लागू करने के संदर्भ में लागू किया जा सकता है, जिसमें किसी विशेष कार्यान्वयन की स्थिति का कोई संदर्भ नहीं है। इसलिए, दोनों अलग-अलग उद्देश्यों के लिए उपयोग करते हैं और दो के बीच चयन वास्तव में परिदृश्य के संदर्भ पर निर्भर करता है।
वैचारिक अंतर:
सार वर्ग कंकाल (यानी आंशिक) इंटरफेस के कार्यान्वयन के लिए मान्य हैं, लेकिन एक मिलान इंटरफ़ेस के बिना मौजूद नहीं होना चाहिए।
इसलिए जब अमूर्त कक्षाएं कम-दृश्यता के लिए प्रभावी रूप से कम हो जाती हैं, तो इंटरफेस के कंकाल कार्यान्वयन, क्या डिफ़ॉल्ट तरीके इसे भी दूर ले जा सकते हैं? निश्चयपूर्वक: नहीं! इंटरफेस को लागू करने के लिए लगभग हमेशा उन क्लास बिल्डिंग टूल्स की आवश्यकता होती है जिनमें डिफ़ॉल्ट तरीकों की कमी होती है। और अगर कुछ इंटरफ़ेस नहीं करता है, तो यह स्पष्ट रूप से एक विशेष मामला है, जिससे आपको भटकना नहीं चाहिए।
जावा 8 में इंटरफेस डिफॉल्ट मेथड्स
जावा 8 " डिफ़ॉल्ट विधि का परिचय देता है ” या (डिफेंडर विधियों) नई सुविधा का देता है, जो डेवलपर को इन इंटरफेस के मौजूदा कार्यान्वयन को तोड़ने के बिना इंटरफेस में नए तरीकों को जोड़ने की अनुमति देता है। यह इंटरफ़ेस को लागू करने की अनुमति देने के लिए लचीलापन प्रदान करता है जो उस स्थिति में डिफ़ॉल्ट के रूप में उपयोग करेगा जहां एक ठोस वर्ग उस पद्धति के लिए एक कार्यान्वयन प्रदान करने में विफल रहता है।
यह कैसे काम करता है यह समझने के लिए छोटे उदाहरण पर विचार करें:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
निम्न वर्ग जावा JDK 8 में सफलतापूर्वक संकलित करेगा,
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
यदि आप OldInterfaceImpl का एक उदाहरण बनाते हैं:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
डिफ़ॉल्ट विधियाँ कभी भी अंतिम नहीं होती हैं, उन्हें सिंक्रनाइज़ नहीं किया जा सकता है और ऑब्जेक्ट के तरीकों को ओवरराइड नहीं कर सकता है। वे हमेशा सार्वजनिक होते हैं, जो छोटे और पुन: प्रयोज्य तरीकों को लिखने की क्षमता को गंभीर रूप से सीमित कर देते हैं।
क्रियान्वयन कक्षाओं को प्रभावित किए बिना एक इंटरफ़ेस को डिफ़ॉल्ट तरीके प्रदान किए जा सकते हैं क्योंकि इसमें एक कार्यान्वयन शामिल है। यदि प्रत्येक इंटरफ़ेस में जोड़ा गया तरीका कार्यान्वयन के साथ परिभाषित किया गया है तो कोई कार्यान्वयन वर्ग प्रभावित नहीं होता है। एक कार्यान्वयन वर्ग इंटरफ़ेस द्वारा प्रदान की गई डिफ़ॉल्ट कार्यान्वयन को ओवरराइड कर सकता है।
डिफ़ॉल्ट तरीके इन इंटरफेस के पुराने कार्यान्वयन को तोड़ने के बिना मौजूदा इंटरफेस में नई कार्यक्षमता जोड़ने में सक्षम हैं।
जब हम एक इंटरफ़ेस का विस्तार करते हैं जिसमें एक डिफ़ॉल्ट विधि होती है, तो हम निम्नलिखित प्रदर्शन कर सकते हैं:
- डिफ़ॉल्ट विधि को ओवरराइड न करें और डिफ़ॉल्ट विधि को इनहेरिट करेगा।
- उपवर्ग में ओवरराइड की गई अन्य विधियों के समान डिफ़ॉल्ट विधि को ओवरराइड करें।
- डिफ़ॉल्ट विधि को अमूर्त के रूप में फिर से परिभाषित करें, जो इसे ओवरराइड करने के लिए उपवर्ग को मजबूर करता है।
डिफ़ॉल्ट विधि का उपयोग कर हल किया गया ForEach विधि संकलन त्रुटि
जावा 8 के लिए, JDK संग्रह बढ़ाया गया है और पूरे संग्रह में विधि जोड़ दी गई है (जो लैम्ब्डा के साथ मिलकर काम करती है)। पारंपरिक तरीके से, कोड नीचे की तरह दिखता है,
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
इस परिणाम के बाद से प्रत्येक कक्षा को संकलित त्रुटियों के साथ लागू किया जाता है, इसलिए एक डिफ़ॉल्ट पद्धति को आवश्यक कार्यान्वयन के साथ जोड़ा गया है ताकि मौजूदा कार्यान्वयन को बदला न जाए।
डिफ़ॉल्ट विधि के साथ Iterable इंटरफ़ेस नीचे है,
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
कार्यान्वयन तंत्रों को तोड़े बिना JDK इंटरफ़ेस में स्ट्रीम जोड़ने के लिए समान तंत्र का उपयोग किया गया है ।
डिफ़ॉल्ट विधि और एकाधिक वंशानुक्रम की समस्याएं
चूंकि जावा क्लास कई इंटरफेस को लागू कर सकता है और प्रत्येक इंटरफ़ेस एक ही विधि हस्ताक्षर के साथ डिफ़ॉल्ट विधि को परिभाषित कर सकता है, इसलिए, विरासत में मिली विधियां एक दूसरे के साथ संघर्ष कर सकती हैं।
उदाहरण के नीचे विचार करें,
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
उपरोक्त कोड निम्नलिखित त्रुटि के साथ संकलित करने में विफल रहेगा,
java: class Impl को डिफॉल्टमैथोड () प्रकार के इंटरफेसए और इंटरफेसबी के लिए असंबंधित चूक मिली
इस वर्ग को ठीक करने के लिए, हमें डिफ़ॉल्ट विधि लागू करने की आवश्यकता है:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
इसके अलावा, यदि हम अपने स्वयं के कार्यान्वयन के बजाय किसी भी सुपर इंटरफ़ेस द्वारा प्रदान की गई डिफ़ॉल्ट कार्यान्वयन को लागू करना चाहते हैं, तो हम निम्नानुसार कर सकते हैं,
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
हम अपनी नई विधि के हिस्से के रूप में किसी भी डिफ़ॉल्ट कार्यान्वयन या दोनों का चयन कर सकते हैं।
जावा इंटरफ़ेस डिफ़ॉल्ट तरीकों के बारे में महत्वपूर्ण बिंदु:
- जावा इंटरफ़ेस डिफ़ॉल्ट तरीके कार्यान्वयन कक्षाओं को तोड़ने के डर के बिना इंटरफेस को विस्तारित करने में हमारी मदद करेंगे।
- जावा इंटरफ़ेस डिफ़ॉल्ट तरीकों ने इंटरफेस और अमूर्त वर्गों के बीच अंतर को कम कर दिया है।
- जावा 8 इंटरफ़ेस डिफ़ॉल्ट तरीके उपयोगिता कक्षाओं से बचने में हमारी मदद करेंगे, जैसे कि सभी कलेक्शन क्लास पद्धति को इंटरफेस में ही प्रदान किया जा सकता है।
- जावा इंटरफ़ेस डिफ़ॉल्ट तरीके आधार कार्यान्वयन कक्षाओं को हटाने में हमारी मदद करेंगे, हम डिफ़ॉल्ट कार्यान्वयन प्रदान कर सकते हैं और कार्यान्वयन कक्षाएं चुन सकते हैं कि कौन सा ओवरराइड करना है।
- इंटरफेस में डिफ़ॉल्ट तरीकों को पेश करने का एक बड़ा कारण लैम्बडा एक्सप्रेशन को सपोर्ट करने के लिए जावा 8 में कलेक्शंस एपीआई को बढ़ाना है।
- यदि पदानुक्रम में किसी भी वर्ग के पास एक ही हस्ताक्षर के साथ एक विधि है, तो डिफ़ॉल्ट तरीके अप्रासंगिक हो जाते हैं। एक डिफ़ॉल्ट विधि java.lang.Object से एक विधि को ओवरराइड नहीं कर सकती है। तर्क बहुत सरल है, यह इसलिए है क्योंकि ऑब्जेक्ट सभी जावा कक्षाओं के लिए आधार वर्ग है। इसलिए भले ही हमारे पास ऑब्जेक्ट क्लास मेथड्स को इंटरफेस में डिफ़ॉल्ट तरीकों के रूप में परिभाषित किया गया है, यह बेकार होगा क्योंकि ऑब्जेक्ट क्लास पद्धति हमेशा उपयोग की जाएगी। इसीलिए भ्रम से बचने के लिए, हमारे पास डिफ़ॉल्ट तरीके नहीं हो सकते हैं जो ऑब्जेक्ट क्लास विधियों को ओवरराइड कर रहे हैं।
- जावा इंटरफ़ेस डिफ़ॉल्ट तरीकों को डिफेंडर विधियों या वर्चुअल एक्सटेंशन विधियों के रूप में भी संदर्भित किया जाता है।
संसाधन लिंक:
- जावा 8 में डिफॉल्ट तरीकों बनाम सार वर्ग के साथ इंटरफ़ेस
- जेडीके 8 युग में सार वर्ग बनाम इंटरफ़ेस
- आभासी विस्तार विधियों के माध्यम से इंटरफ़ेस विकास
जावा इंटरफ़ेस स्थैतिक विधि
जावा इंटरफेस स्टेटिक विधि, कोड उदाहरण, स्थिर विधि बनाम डिफ़ॉल्ट विधि
जावा इंटरफ़ेस स्टैटिक विधि डिफ़ॉल्ट विधि के समान है सिवाय इसके कि हम उन्हें क्रियान्वयन कक्षाओं में ओवरराइड नहीं कर सकते। यह सुविधा कार्यान्वयन कक्षाओं में खराब कार्यान्वयन के अवांछित परिणामों से बचने में हमारी मदद करती है। आइए इसे एक साधारण उदाहरण से देखें।
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
अब आइए एक कार्यान्वयन वर्ग देखें जो खराब कार्यान्वयन के साथ नल () विधि है।
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
ध्यान दें कि Null (String str) एक सरल वर्ग विधि है, यह इंटरफ़ेस विधि को ओवरराइड नहीं कर रही है। उदाहरण के लिए, यदि हम isNull () विधि में @Override एनोटेशन जोड़ देंगे, तो इसका परिणाम संकलक त्रुटि के रूप में होगा।
अब जब हम एप्लिकेशन चलाएंगे, तो हमें आउटपुट मिल जाएगा।
इंटरफ़ेस नल की जाँच करें
Impl Null Check
यदि हम इंटरफ़ेस विधि को स्थैतिक से डिफ़ॉल्ट बनाते हैं, तो हमें निम्न आउटपुट मिलेंगे।
Impl Null Check
MyData प्रिंट ::
Impl Null Check
जावा इंटरफ़ेस स्थिर विधि केवल इंटरफ़ेस विधियों के लिए दृश्यमान है, यदि हम MyDataImpl वर्ग से isNull () विधि को हटाते हैं, तो हम इसे MyDataImpl ऑब्जेक्ट के लिए उपयोग नहीं कर पाएंगे। हालाँकि अन्य स्थैतिक तरीकों की तरह, हम क्लास नाम का उपयोग करके इंटरफ़ेस स्टैटिक विधियों का उपयोग कर सकते हैं। उदाहरण के लिए, एक मान्य कथन होगा:
boolean result = MyData.isNull("abc");
जावा इंटरफेस स्थिर विधि के बारे में महत्वपूर्ण बिंदु:
- जावा इंटरफ़ेस स्थिर विधि इंटरफ़ेस का हिस्सा है, हम इसे क्लास ऑब्जेक्ट के कार्यान्वयन के लिए उपयोग नहीं कर सकते हैं।
- जावा इंटरफेस स्टैटिक मेथड्स यूटिलिटी मेथड प्रदान करने के लिए अच्छे हैं, उदाहरण के लिए नल चेक, कलेक्शन सॉर्टिंग आदि।
- जावा इंटरफ़ेस स्टैटिक मेथड हमें सुरक्षा वर्गों को लागू करने की अनुमति देकर सुरक्षा प्रदान करने में मदद करता है।
- हम ऑब्जेक्ट क्लास विधियों के लिए इंटरफ़ेस स्टैटिक विधि को परिभाषित नहीं कर सकते हैं, हमें कंपाइलर त्रुटि मिलेगी क्योंकि "यह स्टैटिक विधि ऑब्जेक्ट से इंस्टेंस विधि को छिपा नहीं सकती है"। इसका कारण यह है कि जावा में इसकी अनुमति नहीं है, क्योंकि ऑब्जेक्ट सभी वर्गों के लिए आधार वर्ग है और हमारे पास एक कक्षा स्तर की स्थिर विधि और एक ही हस्ताक्षर के साथ एक और उदाहरण विधि नहीं हो सकती है।
- हम जावा इंटरफेस स्टैटिक मेथड्स का उपयोग यूटिलिटी क्लासेस जैसे कलेक्शंस को हटाने और स्टैटिक मेथड्स को संबंधित इंटरफेस में ले जाने के लिए कर सकते हैं, जो खोजने और उपयोग करने में आसान होगा।
जावा फंक्शनल इंटरफेस
इससे पहले कि मैं पद समाप्त करूं, मैं कार्यात्मक इंटरफेस का संक्षिप्त परिचय देना चाहूंगा। बिल्कुल एक अमूर्त विधि वाला एक इंटरफ़ेस कार्यात्मक इंटरफ़ेस के रूप में जाना जाता है।
एक @FunctionalInterface
इंटरफ़ेस को कार्यात्मक इंटरफ़ेस के रूप में चिह्नित करने के लिए एक नया एनोटेशन पेश किया गया है।@FunctionalInterface
एनोटेशन कार्यात्मक इंटरफेस में सार तरीकों के आकस्मिक जोड़ से बचने की सुविधा है। यह वैकल्पिक है लेकिन इसका उपयोग करने के लिए अच्छा अभ्यास है।
कार्यात्मक इंटरफेस लंबे समय से प्रतीक्षित हैं और जावा 8 की बहुत मांग की गई विशेषता है क्योंकि यह हमें लैम्बडा के भावों का उपयोग करने के लिए उन्हें तुरंत सक्षम बनाता है। एक नया पैकेज java.util.f लैम्बडा एक्सप्रेशन और विधि संदर्भ के लिए लक्ष्य प्रकार प्रदान करने के लिए कार्यात्मक इंटरफेस के गुच्छा के साथ जोड़ा जाता है। हम भविष्य के पदों में कार्यात्मक इंटरफेस और लैम्ब्डा अभिव्यक्तियों पर ध्यान देंगे।
संसाधन स्थान:
- जावा 8 इंटरफ़ेस परिवर्तन - स्थिर विधि, डिफ़ॉल्ट विधि