CodeGym /Java Blog /अनियमित /सार वर्गों और इंटरफेस के बीच का अंतर
John Squirrels
स्तर 41
San Francisco

सार वर्गों और इंटरफेस के बीच का अंतर

अनियमित ग्रुप में प्रकाशित
नमस्ते! इस पाठ में, हम इस बारे में बात करेंगे कि कैसे सार वर्ग इंटरफेस से भिन्न होते हैं और सामान्य सार वर्गों के साथ कुछ उदाहरणों पर विचार करेंगे। अमूर्त वर्ग और इंटरफेस के बीच का अंतर - 1हमने अमूर्त वर्ग और इंटरफ़ेस के बीच अंतर के लिए एक अलग पाठ समर्पित किया है, क्योंकि यह विषय बहुत महत्वपूर्ण है। आपसे भविष्य के 90% साक्षात्कारों में इन अवधारणाओं के बीच के अंतर के बारे में पूछा जाएगा। इसका मतलब है कि आपको यह पता होना चाहिए कि आप क्या पढ़ रहे हैं। और अगर आप कुछ पूरी तरह से नहीं समझते हैं, तो अतिरिक्त स्रोत पढ़ें। तो, हम जानते हैं कि अमूर्त वर्ग क्या है और इंटरफ़ेस क्या है। अब हम उनके मतभेदों पर जाएंगे।
  1. एक इंटरफ़ेस केवल व्यवहार का वर्णन करता है। इसका कोई राज्य नहीं है। लेकिन एक सार वर्ग में राज्य शामिल है: यह दोनों का वर्णन करता है।

    Birdउदाहरण के लिए, सार वर्ग और इंटरफ़ेस लें CanFly:

    
    public abstract class Bird {
       private String species;
       private int age;
    
       public abstract void fly();
    
       public String getSpecies() {
           return species;
       }
    
       public void setSpecies(String species) {
           this.species = species;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    }
    

    चलिए एक MockingJayबर्ड क्लास बनाते हैं और इसे इनहेरिट करते हैं Bird:

    
    public class MockingJay extends Bird {
    
       @Override
       public void fly() {
           System.out.println("Fly, bird!");
       }
    
       public static void main(String[] args) {
    
           MockingJay someBird = new MockingJay();
           someBird.setAge(19);
           System.out.println(someBird.getAge());
       }
    }
    

    जैसा कि आप देख सकते हैं, हम अमूर्त वर्ग की स्थिति - इसके speciesऔर ageचरों तक आसानी से पहुँच सकते हैं।

    लेकिन अगर हम इंटरफ़ेस के साथ ऐसा ही करने की कोशिश करते हैं, तो तस्वीर अलग होती है। हम इसमें चर जोड़ने का प्रयास कर सकते हैं:

    
    public interface CanFly {
    
       String species = new String();
       int age = 10;
    
       public void fly();
    }
    
    public interface CanFly {
    
       private String species = new String(); // Error
       private int age = 10; // Another error
    
       public void fly();
    }
    

    हम एक इंटरफ़ेस के अंदर निजी चर भी घोषित नहीं कर सकते । क्यों? क्योंकि उपयोगकर्ता से कार्यान्वयन को छिपाने के लिए निजी संशोधक बनाया गया था। और इसके अंदर एक इंटरफ़ेस का कोई कार्यान्वयन नहीं है: छिपाने के लिए कुछ भी नहीं है।

    एक इंटरफ़ेस केवल व्यवहार का वर्णन करता है। तदनुसार, हम एक इंटरफ़ेस के अंदर गेटर्स और सेटर्स को लागू नहीं कर सकते। यह इंटरफेस की प्रकृति है: उन्हें व्यवहार के साथ काम करने की जरूरत है, राज्य की नहीं।

    जावा 8 ने कार्यान्वयन वाले इंटरफेस के लिए डिफ़ॉल्ट तरीके पेश किए। आप उनके बारे में पहले से ही जानते हैं, इसलिए हम अपनी बात नहीं दोहराएंगे।

  2. एक सार वर्ग उन वर्गों को जोड़ता है और एकजुट करता है जो बहुत निकट से संबंधित हैं। एक ही समय में, एक एकल इंटरफ़ेस उन वर्गों द्वारा कार्यान्वित किया जा सकता है जिनमें बिल्कुल कुछ भी सामान्य नहीं है।

    आइए पक्षियों के साथ अपने उदाहरण पर लौटते हैं।

    Birdउस वर्ग पर आधारित पक्षियों को बनाने के लिए हमारे सार वर्ग की जरूरत है। केवल पक्षी और कुछ नहीं! बेशक, विभिन्न प्रकार के पक्षी होंगे।

    अमूर्त वर्ग और इंटरफेस के बीच का अंतर - 2

    इंटरफेस के साथ CanFly, हर कोई अपने तरीके से आगे बढ़ता है। यह केवल अपने नाम से जुड़े व्यवहार (उड़ान) का वर्णन करता है। कई असंबंधित चीजें 'उड़ सकती हैं'।

    अमूर्त वर्ग और इंटरफेस के बीच का अंतर - 3

    ये 4 संस्थाएँ एक दूसरे से संबंधित नहीं हैं। वे सब जीवित भी नहीं हैं। हालाँकि, वे सभी CanFly

    हम एक सार वर्ग का उपयोग करके उनका वर्णन नहीं कर सके। वे समान स्थिति या समान फ़ील्ड साझा नहीं करते हैं। एक विमान को परिभाषित करने के लिए, हमें संभवतः मॉडल, उत्पादन वर्ष और यात्रियों की अधिकतम संख्या के लिए फ़ील्ड की आवश्यकता होगी। कार्लसन के लिए, हमें उन सभी मिठाइयों के लिए खेतों की आवश्यकता होगी जो उसने आज खाईं, और उन खेलों की एक सूची जो वह अपने छोटे भाई के साथ खेलेगा। एक मच्छर के लिए, ...उह... मुझे पता भी नहीं... शायद, एक 'झुंझलाहट का स्तर'? :)

    मुद्दा यह है कि हम उनका वर्णन करने के लिए एक सार वर्ग का उपयोग नहीं कर सकते। वे बहुत अलग हैं। लेकिन उनका साझा व्यवहार है: वे उड़ सकते हैं। एक इंटरफ़ेस दुनिया में हर उस चीज़ का वर्णन करने के लिए एकदम सही है जो उड़ सकती है, तैर सकती है, कूद सकती है या कुछ अन्य व्यवहार प्रदर्शित कर सकती है।

  3. कक्षाएं आप जितने चाहें उतने इंटरफेस लागू कर सकती हैं, लेकिन वे केवल एक वर्ग को इनहेरिट कर सकती हैं।

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

मानक इंटरफेस: इनपुटस्ट्रीम और आउटपुटस्ट्रीम

हम पहले ही इनपुट और आउटपुट स्ट्रीम के लिए जिम्मेदार विभिन्न वर्गों पर जा चुके हैं। आइए विचार करें InputStreamऔर OutputStream। सामान्य तौर पर, ये बिल्कुल इंटरफेस नहीं हैं, बल्कि पूरी तरह से वास्तविक अमूर्त वर्ग हैं। अब आप जानते हैं कि इसका क्या मतलब है, इसलिए उनके साथ काम करना बहुत आसान हो जाएगा :) InputStreamबाइट इनपुट के लिए जिम्मेदार एक अमूर्त वर्ग है। जावा में कई वर्ग हैं जो इनहेरिट करते हैं InputStream। उनमें से प्रत्येक को विभिन्न स्रोतों से डेटा प्राप्त करने के लिए डिज़ाइन किया गया है। क्योंकि InputStreamमाता-पिता है, यह कई तरीके प्रदान करता है जो डेटा स्ट्रीम के साथ काम करना आसान बनाता है। प्रत्येक वंशज के InputStreamपास ये विधियाँ हैं:
  • int available()पढ़ने के लिए उपलब्ध बाइट्स की संख्या लौटाता है;
  • close()इनपुट स्ट्रीम बंद करता है;
  • int read()स्ट्रीम में अगली उपलब्ध बाइट का पूर्णांक प्रतिनिधित्व लौटाता है। यदि धारा का अंत हो गया है, -1 वापस आ जाएगा;
  • int read(byte[] buffer)बाइट्स को बफर में पढ़ने की कोशिश करता है, और पढ़े गए बाइट्स की संख्या लौटाता है। जब यह फ़ाइल के अंत तक पहुँचता है, तो यह -1 लौटाता है;
  • int read(byte[] buffer, int byteOffset, int byteCount)बाइट्स के एक ब्लॉक का हिस्सा लिखता है। इसका उपयोग तब किया जाता है जब बाइट सरणी पूरी तरह से भरी नहीं हो सकती है। जब यह फ़ाइल के अंत तक पहुँचता है, तो यह -1 लौटाता है;
  • long skip(long byteCount)इनपुट स्ट्रीम में बाइटकाउंट बाइट्स को छोड़ देता है, और अनदेखा किए गए बाइट्स की संख्या लौटाता है।
मेरा सुझाव है कि आप विधियों की पूरी सूची का अध्ययन करें । वास्तव में दस से अधिक बाल वर्ग हैं। उदाहरण के लिए, यहाँ कुछ हैं:
  1. FileInputStream: सबसे आम प्रकार InputStream। इसका उपयोग किसी फ़ाइल से जानकारी पढ़ने के लिए किया जाता है;
  2. StringBufferInputStream: का एक अन्य सहायक प्रकार InputStream। यह एक स्ट्रिंग को एक में परिवर्तित करता है InputStream;
  3. BufferedInputStream: एक बफ़र्ड इनपुट स्ट्रीम। प्रदर्शन को बढ़ाने के लिए इसका सबसे अधिक उपयोग किया जाता है।
याद है जब हमने जाकर BufferedReaderकहा था कि आपको इसका उपयोग करने की आवश्यकता नहीं है? जब हम लिखते हैं:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
…आपको उपयोग करने की आवश्यकता नहीं है BufferedReader: एक InputStreamReaderकाम कर सकता है। लेकिन BufferedReaderप्रदर्शन में सुधार करता है और अलग-अलग वर्णों के बजाय डेटा की संपूर्ण पंक्तियों को भी पढ़ सकता है। पर भी यही बात लागू होती है BufferedInputStream! वर्ग इनपुट डिवाइस को लगातार एक्सेस किए बिना एक विशेष बफर में इनपुट डेटा जमा करता है। आइए एक उदाहरण पर विचार करें:

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class BufferedInputExample {

   public static void main(String[] args) throws Exception {
       InputStream inputStream = null;
       BufferedInputStream buffer = null;

       try {

           inputStream = new FileInputStream("D:/Users/UserName/someFile.txt");

           buffer = new BufferedInputStream(inputStream);

           while(buffer.available()>0) {

               char c = (char)buffer.read();

                System.out.println("Character read: " + c);
           }
       } catch(Exception e) {

           e.printStackTrace();

       } finally {

           inputStream.close();
           buffer.close();
       }
   }
}
इस उदाहरण में, हम ' D:/Users/UserName/someFile.txt ' पर कंप्यूटर पर स्थित फ़ाइल से डेटा पढ़ते हैं । हम 2 ऑब्जेक्ट बनाते हैं - a FileInputStreamऔर a BufferedInputStreamजो इसे 'लपेटता' है। फिर हम फ़ाइल से बाइट पढ़ते हैं और उन्हें वर्णों में परिवर्तित करते हैं। और हम ऐसा तब तक करते हैं जब तक कि फाइल समाप्त नहीं हो जाती। जैसा कि आप देख सकते हैं, यहाँ कुछ भी जटिल नहीं है। आप इस कोड को कॉपी कर सकते हैं और इसे अपने कंप्यूटर पर वास्तविक फ़ाइल पर चला सकते हैं :) OutputStreamवर्ग एक अमूर्त वर्ग है जो बाइट्स के आउटपुट स्ट्रीम का प्रतिनिधित्व करता है। जैसा कि आप पहले से ही जानते हैं, यह एक के विपरीत है InputStream। यह कहीं से डेटा पढ़ने के लिए ज़िम्मेदार नहीं है, बल्कि कहीं डेटा भेजने के लिए ज़िम्मेदार है । जैसे InputStream, यह सार वर्ग अपने सभी वंशजों को सुविधाजनक तरीकों का एक सेट देता है:
  • void close()आउटपुट स्ट्रीम बंद करता है;
  • void flush()सभी आउटपुट बफ़र्स साफ़ करता है;
  • abstract void write(int oneByte)आउटपुट स्ट्रीम में 1 बाइट लिखता है;
  • void write(byte[] buffer)आउटपुट स्ट्रीम में एक बाइट सरणी लिखता है;
  • void write(byte[] buffer, int offset, int count)ऑफ़सेट स्थिति से प्रारंभ करते हुए, सरणी से गिनती बाइट्स की एक श्रृंखला लिखता है।
यहाँ वर्ग के कुछ वंशज हैं OutputStream:
  1. DataOutputStream. एक आउटपुट स्ट्रीम जिसमें मानक जावा डेटा प्रकार लिखने के तरीके शामिल हैं।

    आदिम जावा डेटा प्रकार और तार लिखने के लिए एक बहुत ही सरल वर्ग। आप शायद स्पष्टीकरण के बिना भी निम्न कोड को समझेंगे:

    
    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           DataOutputStream dos = new DataOutputStream(new FileOutputStream("testFile.txt"));
    
           dos.writeUTF("SomeString");
           dos.writeInt(22);
           dos.writeDouble(1.21323);
           dos.writeBoolean(true);
    
       }
    }
    

    इसमें प्रत्येक प्रकार के लिए अलग-अलग तरीके हैं - writeDouble(), writeLong(), writeShort(), और इसी तरह।


  2. FileOutputStream. यह वर्ग डिस्क पर फ़ाइल में डेटा भेजने के लिए एक तंत्र लागू करता है। वैसे, हम इसे पिछले उदाहरण में पहले ही इस्तेमाल कर चुके हैं। क्या तुमने ध्यान दिया? हमने इसे DataOutputStream में पास कर दिया, जिसने 'रैपर' के रूप में काम किया।

  3. BufferedOutputStream. एक बफ़र्ड आउटपुट स्ट्रीम। यहाँ कुछ भी जटिल नहीं है। इसका उद्देश्य BufferedInputStream(या BufferedReader) के अनुरूप है। डेटा के सामान्य अनुक्रमिक पढ़ने के बजाय, यह एक विशेष 'संचयी' बफर का उपयोग करके डेटा लिखता है। बफ़र डेटा सिंक तक पहुँचने की संख्या को कम करना संभव बनाता है, जिससे प्रदर्शन बढ़ता है।

    
    import java.io.*;
    
    public class DataOutputStreamExample {
    
         public static void main(String[] args) throws IOException {
    
               FileOutputStream outputStream = new FileOutputStream("D:/Users/Username/someFile.txt");
               BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
    
               String text = "I love Java!"; // We'll convert this string to a byte array and write it to a file
    
               byte[] buffer = text.getBytes();
    
               bufferedStream.write(buffer, 0, buffer.length);
         }
    }
    

    दोबारा, आप स्वयं इस कोड के साथ खेल सकते हैं और सत्यापित कर सकते हैं कि यह आपके कंप्यूटर पर वास्तविक फाइलों पर काम करेगा।

FileInputStreamहमारे पास , FileOutputStreamऔर के बारे में एक अलग पाठ होगा BuffreredInputStream, इसलिए पहले परिचय के लिए यह पर्याप्त जानकारी है। इतना ही! हम आशा करते हैं कि आप इंटरफेस और अमूर्त कक्षाओं के बीच के अंतर को समझ गए हैं और किसी भी प्रश्न का उत्तर देने के लिए तैयार हैं, यहां तक ​​कि ट्रिक प्रश्नों के लिए भी :)
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION