नमस्ते! आज हम जावा में एक महत्वपूर्ण अवधारणा के बारे में बात करने जा रहे हैं: इंटरफेस। यह शब्द शायद आपसे परिचित है। उदाहरण के लिए, अधिकांश कंप्यूटर प्रोग्राम और गेम में इंटरफेस होते हैं। एक व्यापक अर्थ में, एक इंटरफ़ेस एक प्रकार का 'रिमोट कंट्रोल' है जो दो इंटरेक्टिंग पार्टियों को जोड़ता है। रोजमर्रा की जिंदगी में एक इंटरफेस का एक सरल उदाहरण एक टीवी रिमोट कंट्रोल है। यह दो वस्तुओं - एक व्यक्ति और एक टीवी को जोड़ता है - और विभिन्न कार्य करता है: वॉल्यूम बढ़ाएँ या घटाएँ, चैनल स्विच करें, और टीवी चालू या बंद करें। दूसरे पक्ष को कार्रवाई करने के लिए एक पक्ष (व्यक्ति) को इंटरफ़ेस (रिमोट कंट्रोल पर एक बटन दबाएं) तक पहुंचने की आवश्यकता है। उदाहरण के लिए, टीवी को अगले चैनल में बदलने के लिए। क्या अधिक है, उपयोगकर्ता नहीं करता है यह जानने की जरूरत नहीं है कि टीवी कैसे व्यवस्थित किया जाता है या चैनल बदलने की प्रक्रिया को आंतरिक रूप से कैसे लागू किया जाता है। उपयोगकर्ता के पास केवल एक चीज है जो इंटरफ़ेस है। मुख्य उद्देश्य वांछित परिणाम प्राप्त करना है। इसका प्रोग्रामिंग और जावा से क्या लेना-देना है? सब कुछ :) एक इंटरफ़ेस बनाना एक नियमित वर्ग बनाने के समान है, लेकिन इसके बजाय शब्द का उपयोग करनावर्ग , हम शब्द इंटरफ़ेस का संकेत देते हैं । आइए सबसे सरल जावा इंटरफ़ेस देखें, देखें कि यह कैसे काम करता है और हमें इसकी आवश्यकता क्यों है:
आपने
आइए
public interface CanSwim {
public void swim();
}
हमने एक कैनस्विम इंटरफ़ेस बनाया है। यह हमारे रिमोट कंट्रोल की तरह है, लेकिन एक 'बटन' के साथ: स्विम () विधि। लेकिन हम इस रिमोट कंट्रोलर का उपयोग कैसे करते हैं? ऐसा करने के लिए, हमें एक विधि लागू करने की आवश्यकता है, अर्थात हमारा रिमोट कंट्रोल बटन। एक इंटरफ़ेस का उपयोग करने के लिए, हमारे कार्यक्रम में कुछ वर्गों को इसके तरीकों को लागू करना चाहिए। आइए एक ऐसे वर्ग का आविष्कार करें जिसकी वस्तुएं 'तैर सकती हैं'। उदाहरण के लिए, एक बतख वर्ग फिट बैठता है:
public class Duck implements CanSwim {
public void swim() {
System.out.println("Duck, swim!");
}
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim();
}
}
"हम यहां क्या देखते हैं? डक क्लास ' इंप्लीमेंट्स ' कीवर्ड द्वारा कैनस्विम इंटरफेस के साथ 'संबद्ध' है । आपको याद होगा कि हमने विरासत के माध्यम से दो वर्गों को जोड़ने के लिए एक समान तंत्र का उपयोग किया था, लेकिन उस स्थिति में हमने शब्द का विस्तार किया। पूर्ण स्पष्टता, हम ' पब्लिक क्लास डक इम्प्लीमेंट्स कैनस्विम ' का शाब्दिक रूप से अनुवाद कर सकते हैं: 'पब्लिक डक क्लास कैनस्विम इंटरफ़ेस को लागू करता है'। इसका मतलब है कि एक इंटरफ़ेस से जुड़े एक वर्ग को अपने सभी तरीकों को लागू करना चाहिए। नोट: हमारी कक्षा, ठीक उसी तरह इंटरफ़ेस , एक विधि है, और इसमें कुछ तर्क शामिल हैं। यह एक अनिवार्य आवश्यकता है। अगर हम सिर्फ लिखते हैंDuck
CanSwim
swim()
public class Duck implements CanSwim
swim()
क्लास में कोई मेथड बनाए बिना Duck
, कंपाइलर हमें एक एरर देगा: डक एब्स्ट्रैक्ट नहीं है और CanSwim में एब्स्ट्रैक्ट मेथड स्विम () को ओवरराइड नहीं करता है क्यों? ऐसा क्यूँ होता है? यदि हम टीवी के उदाहरण का उपयोग करके त्रुटि की व्याख्या करते हैं, तो यह किसी को 'चेंज चैनल' बटन के साथ टीवी रिमोट कंट्रोल देने जैसा होगा जो चैनल नहीं बदल सकता। आप जितना चाहें बटन दबा सकते हैं, लेकिन यह काम नहीं करेगा। रिमोट कंट्रोल अपने आप चैनल नहीं बदलता है: यह केवल टीवी को एक संकेत भेजता है, जो चैनल बदलने की जटिल प्रक्रिया को लागू करता है। और इसलिए यह हमारे बतख के साथ है: इसे तैरना आना चाहिए ताकि इसे CanSwim
इंटरफ़ेस का उपयोग करके बुलाया जा सके। अगर यह नहीं जानता कि कैसे,CanSwim
इंटरफ़ेस दो पक्षों - व्यक्ति और कार्यक्रम को जोड़ता नहीं है। व्यक्ति कार्यक्रम के अंदर तैरने swim()
के लिए विधि का उपयोग नहीं कर पाएगा । Duck
अब आप अधिक स्पष्ट रूप से समझते हैं कि इंटरफेस किस लिए हैं। एक इंटरफ़ेस उस व्यवहार का वर्णन करता है जो इंटरफ़ेस को लागू करने वाली कक्षाओं में होना चाहिए। 'व्यवहार' विधियों का संग्रह है। यदि हम कई संदेशवाहक बनाना चाहते हैं, तो सबसे आसान काम एक Messenger
इंटरफ़ेस बनाना है। हर संदेशवाहक को क्या चाहिए? बुनियादी स्तर पर, उन्हें संदेश प्राप्त करने और भेजने में सक्षम होना चाहिए।
public interface Messenger{
public void sendMessage();
public void getMessage();
}
अब हम बस अपना मैसेंजर क्लास बना सकते हैं जो संबंधित इंटरफ़ेस को लागू करता है। कंपाइलर ही हमें अपनी कक्षाओं में लागू करने के लिए 'मजबूर' करेगा। तार:
public class Telegram implements Messenger {
public void sendMessage() {
System.out.println("Sending a Telegram message!");
}
public void getMessage() {
System.out.println("Receiving a Telegram message!");
}
}
व्हाट्सएप:
public class WhatsApp implements Messenger {
public void sendMessage() {
System.out.println("Sending a WhatsApp message!");
}
public void getMessage() {
System.out.println("Reading a WhatsApp message!");
}
}
वाइबर:
public class Viber implements Messenger {
public void sendMessage() {
System.out.println("Sending a Viber message!");
}
public void getMessage() {
System.out.println("Receiving a Viber message!");
}
}
इससे क्या लाभ मिलते हैं? उनमें से सबसे महत्वपूर्ण ढीला युग्मन है। कल्पना कीजिए कि हम एक ऐसा प्रोग्राम डिजाइन कर रहे हैं जो क्लाइंट डेटा एकत्र करेगा। क्लाइंट किस विशिष्ट संदेशवाहक का उपयोग कर रहा है, यह इंगित करने के लिए वर्ग Client
को निश्चित रूप से एक फ़ील्ड की आवश्यकता होती है। इंटरफेस के बिना, यह अजीब लगेगा:
public class Client {
private WhatsApp whatsApp;
private Telegram telegram;
private Viber viber;
}
हमने तीन फ़ील्ड बनाए, लेकिन क्लाइंट के पास केवल एक संदेशवाहक हो सकता है। हम बस नहीं जानते कि कौन सा है। इसलिए क्लाइंट के साथ संवाद करने में सक्षम होने के लिए हमें कक्षा में हर संभावना को जोड़ना होगा। यह पता चला है कि उनमें से एक या दो हमेशा होंगे null
, कार्यक्रम द्वारा पूरी तरह से अनावश्यक। इसके बजाय हमारे इंटरफ़ेस का उपयोग करना बेहतर है:
public class Client {
private Messenger messenger;
}
यह लूज़ कपलिंग का एक उदाहरण है! कक्षा में एक विशिष्ट संदेशवाहक वर्ग को निर्दिष्ट करने के बजाय Client
, हम केवल यह संकेत देते हैं कि ग्राहक के पास एक संदेशवाहक है। कार्यक्रम चलने के दौरान वास्तव में कौन सा निर्धारित किया जाएगा। लेकिन हमें इसके लिए इंटरफेस की जरूरत क्यों है? उन्हें भाषा में क्यों जोड़ा गया? यह एक अच्छा प्रश्न है — और सही प्रश्न है! क्या हम साधारण वंशानुक्रम का उपयोग करके समान परिणाम प्राप्त नहीं कर सकते? Messenger
माता-पिता के रूप में कक्षा, और , Viber
और Telegram
बच्चों WhatsApp
के रूप में। वाकई, यह मुमकिन है। लेकिन एक रोड़ा है। जैसा कि आप पहले से ही जानते हैं, जावा में कोई एकाधिक वंशानुक्रम नहीं है। लेकिन कई इंटरफेस के लिए समर्थन है। एक वर्ग जितने चाहें उतने इंटरफेस लागू कर सकता है। कल्पना कीजिए कि हमारे पास एक Smartphone
वर्ग है जिसमें एक हैApp
फ़ील्ड, जो स्मार्टफ़ोन पर इंस्टॉल किए गए ऐप का प्रतिनिधित्व करता है।
public class Smartphone {
private App app;
}
बेशक, एक ऐप और मैसेंजर समान हैं, लेकिन फिर भी वे अलग चीजें हैं। मैसेंजर के मोबाइल और डेस्कटॉप संस्करण हो सकते हैं, लेकिन ऐप विशेष रूप से एक मोबाइल ऐप का प्रतिनिधित्व करता है। यहाँ सौदा है - यदि हम विरासत का उपयोग करते हैं, तो हम कक्षा Telegram
में कोई वस्तु नहीं जोड़ पाएंगे। Smartphone
आखिरकार, Telegram
कक्षा एक साथ विरासत में नहीं मिल सकती है App
और Messenger
! और हम पहले ही इसे इनहेरिट कर चुके हैं Messenger
और इसे Client
क्लास में जोड़ चुके हैं। लेकिन Telegram
वर्ग दोनों इंटरफेस को आसानी से लागू कर सकता है! Client
तदनुसार, हम कक्षा को एक Telegram
वस्तु के रूप में दे सकते हैं Messenger
, और हम इसे Smartphone
कक्षा को एक के रूप में दे सकते हैं App
। यहां बताया गया है कि आप ऐसा कैसे करते हैं:
public class Telegram implements Application, Messenger {
// ...methods
}
public class Client {
private Messenger messenger;
public Client() {
this.messenger = new Telegram();
}
}
public class Smartphone {
private Application application;
public Smartphone() {
this.application = new Telegram();
}
}
अब हम Telegram
कक्षा का उपयोग कर रहे हैं कि हम कैसे चाहते हैं। कुछ जगहों पर, यह एक के रूप में कार्य करता है App
। अन्य स्थानों पर, यह एक के रूप में कार्य करता है Messenger
। आपने निश्चित रूप से पहले ही देखा है कि इंटरफ़ेस विधियाँ हमेशा 'खाली' होती हैं, अर्थात उनका कोई कार्यान्वयन नहीं होता है। इसका कारण सरल है: इंटरफ़ेस व्यवहार का वर्णन करता है, लेकिन इसे लागू नहीं करता है। 'इंटरफ़ेस को लागू करने वाली सभी वस्तुओं को CanSwim
तैरने में सक्षम होना चाहिए': यह सब इंटरफ़ेस हमें बताता है। मछलियों, बत्तखों और घोड़ों के तैरने का विशिष्ट तरीका , , और के लिए एक Fish
प्रश्न Duck
हैHorse
कक्षाएं, इंटरफ़ेस नहीं। जैसे टीवी के लिए चैनल बदलना एक टास्क है। रिमोट आपको इसके लिए बस एक बटन देता है। हालाँकि, जावा 8 में एक दिलचस्प जोड़ दिखाई दिया - डिफ़ॉल्ट तरीके। उदाहरण के लिए, आपके इंटरफ़ेस में 10 विधियाँ हैं। उनमें से 9 का अलग-अलग वर्गों में अलग-अलग कार्यान्वयन है, लेकिन एक को सभी के लिए समान रूप से लागू किया गया है। पहले, जावा 8 से पहले, इंटरफ़ेस विधियों का कोई कार्यान्वयन नहीं था: संकलक ने तुरंत एक त्रुटि दी। अब आप ऐसा कुछ कर सकते हैं:
public interface CanSwim {
public default void swim() {
System.out.println("Swim!");
}
public void eat();
public void run();
}
कीवर्ड का उपयोग करते हुए default
, हमने डिफ़ॉल्ट क्रियान्वयन के साथ एक इंटरफ़ेस विधि बनाई है। हमें दो अन्य तरीकों के लिए अपना स्वयं का कार्यान्वयन प्रदान करने की आवश्यकता है - eat()
और run()
- लागू करने वाले सभी वर्गों में CanSwim
। हमें इसे विधि के साथ करने की आवश्यकता नहीं है swim()
: कार्यान्वयन प्रत्येक वर्ग में समान होगा। वैसे, आप पहले से ही पिछले कार्यों में इंटरफेस देख चुके हैं, भले ही आपने नोटिस नहीं किया हो :) यहाँ एक ज्वलंत उदाहरण है: 
List
और Set
इंटरफेस के साथ काम किया है! अधिक सटीक रूप से, आपने उनके कार्यान्वयन के साथ काम किया है — ArrayList
, LinkedList
, HashSet
, आदि। वही आरेख स्पष्ट रूप से एक उदाहरण देता है जहां एक वर्ग एक ही समय में कई इंटरफेस लागू करता है। उदाहरण के लिए, और LinkedList
लागू करता हैList
Deque
(डबल-एंडेड कतार) इंटरफेस। आप इंटरफ़ेस से परिचित हैं , या इसके कार्यान्वयन Map
के साथ । HashMap
वैसे, यह आरेख एक विशेषता दिखाता है: इंटरफेस को अन्य इंटरफेस का उत्तराधिकारी बनाया जा सकता है। इंटरफ़ेस SortedMap
इनहेरिट करता है Map
, जबकि Deque
इनहेरिट करता है Queue
। यह आवश्यक है यदि आप इंटरफेस के बीच संबंध दिखाना चाहते हैं, जहां एक इंटरफेस दूसरे का एक विस्तारित संस्करण है। Queue
इंटरफ़ेस के साथ एक उदाहरण पर विचार करें। हमने अभी समीक्षा नहीं की हैQueues
, लेकिन यह अपेक्षाकृत सरल है और स्टोर पर एक सामान्य क्यू या लाइन की तरह काम करता है। आप कतार के अंत में केवल आइटम जोड़ सकते हैं, और उन्हें केवल शुरुआत से ही ले सकते हैं। किसी बिंदु पर, दोनों सिरों पर आइटम जोड़ने और लेने के लिए डेवलपर्स को कतार के एक उन्नत संस्करण की आवश्यकता थी। Deque
इसलिए उन्होंने एक इंटरफ़ेस बनाया , जो एक डबल-एंडेड कतार है। इसमें साधारण कतार के सभी तरीके हैं। आखिरकार, यह डबल-एंडेड कतार का जनक है, लेकिन यह नए तरीके भी जोड़ता है।
GO TO FULL VERSION