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. ক্লাসগুলি আপনি যতগুলি চান ততগুলি ইন্টারফেস প্রয়োগ করতে পারে তবে তারা কেবল একটি ক্লাসের উত্তরাধিকারী হতে পারে।

    আমরা ইতিমধ্যে এটি একাধিকবার উল্লেখ করেছি। জাভাতে ক্লাসের একাধিক উত্তরাধিকার নেই, তবে এটি ইন্টারফেসের একাধিক উত্তরাধিকার সমর্থন করে। এই পয়েন্টটি পূর্ববর্তীটির থেকে কিছু অংশে অনুসরণ করে: একটি ইন্টারফেস অনেকগুলি বিভিন্ন শ্রেণিকে সংযুক্ত করে যেগুলির মধ্যে প্রায়শই মিল থাকে না, যখন একটি বিমূর্ত শ্রেণী খুব ঘনিষ্ঠভাবে সম্পর্কিত ক্লাসগুলির একটি গ্রুপের জন্য তৈরি করা হয়। অতএব, এটি বোধগম্য হয় যে আপনি শুধুমাত্র এই ধরনের একটি শ্রেণীর উত্তরাধিকারী হতে পারেন। একটি বিমূর্ত শ্রেণী একটি 'is-a' সম্পর্ককে বর্ণনা করে।

স্ট্যান্ডার্ড ইন্টারফেস: ইনপুটস্ট্রিম এবং আউটপুটস্ট্রিম

আমরা ইতিমধ্যেই ইনপুট এবং আউটপুট স্ট্রীমগুলির জন্য দায়ী বিভিন্ন শ্রেণীতে গিয়েছি। আসুন বিবেচনা করা যাক 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)ইনপুট স্ট্রীমে 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তাই প্রথম পরিচিতের জন্য এটি যথেষ্ট তথ্য। এটাই! আমরা আশা করি আপনি ইন্টারফেস এবং বিমূর্ত ক্লাসের মধ্যে পার্থক্য বুঝতে পেরেছেন এবং যে কোনও প্রশ্নের উত্তর দিতে প্রস্তুত, এমনকি ট্রিক প্রশ্ন :)
মন্তব্য
  • জনপ্রিয়
  • নতুন
  • পুরানো
মন্তব্য লেখার জন্য তোমাকে অবশ্যই সাইন ইন করতে হবে
এই পাতায় এখনও কোনো মন্তব্য নেই