CodeGym /مدونة جافا /Random-AR /الفرق بين الطبقات المجردة والواجهات
John Squirrels
مستوى
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();
    }

    لا يمكننا حتى الإعلان عن المتغيرات الخاصة داخل الواجهة. لماذا؟ لأنه تم إنشاء المعدل الخاص لإخفاء التنفيذ عن المستخدم. ولا تحتوي الواجهة على تطبيق بداخلها: لا يوجد شيء يمكن إخفاؤه.

    الواجهة تصف السلوك فقط. وفقًا لذلك، لا يمكننا تنفيذ الحروف والمحددات داخل الواجهة. هذه هي طبيعة الواجهات: فهي ضرورية للتعامل مع السلوك، وليس الحالة.

    قدم Java 8 الطرق الافتراضية للواجهات التي لها تطبيق. أنت تعرف عنها بالفعل، لذلك لن نكرر أنفسنا.

  2. تربط الفئة المجردة وتوحد الفئات المرتبطة ارتباطًا وثيقًا. وفي الوقت نفسه، يمكن تنفيذ واجهة واحدة بواسطة فئات ليس لديها أي شيء مشترك على الإطلاق.

    دعونا نعود إلى مثالنا مع الطيور.

    هناك حاجة إلى فصلنا Birdالتجريدي لإنشاء الطيور التي تعتمد على تلك الفئة. مجرد الطيور ولا شيء غير ذلك! وبطبيعة الحال، سيكون هناك أنواع مختلفة من الطيور.

    الفرق بين الفئات المجردة والواجهات - 2

    مع CanFlyالواجهة، يستطيع الجميع العمل بطريقتهم الخاصة. فهو يصف فقط السلوك (الطيران) المرتبط باسمه. العديد من الأشياء غير ذات الصلة "يمكن أن تطير".

    الفرق بين الفئات المجردة والواجهات - 3

    هذه الكيانات الأربعة ليست مرتبطة ببعضها البعض. إنهم ليسوا جميعًا أحياء. ومع ذلك، كلهم CanFly.

    لا يمكننا وصفهم باستخدام فئة مجردة. ولا يتشاركون في نفس الحالة أو الحقول المتطابقة. لتحديد طائرة، ربما نحتاج إلى حقول للطراز وسنة الإنتاج والحد الأقصى لعدد الركاب. بالنسبة لكارلسون، سنحتاج إلى حقول لجميع الحلويات التي أكلها اليوم، وقائمة بالألعاب التي سيلعبها مع أخيه الصغير. بالنسبة للبعوضة، ...آه... أنا لا أعرف حتى... ربما، "مستوى الانزعاج"؟ :)

    النقطة المهمة هي أنه لا يمكننا استخدام فئة مجردة لوصفها. إنهم مختلفون للغاية. لكن لديهم سلوك مشترك: يمكنهم الطيران. تعد الواجهة مثالية لوصف كل شيء في العالم يمكنه الطيران أو السباحة أو القفز أو إظهار بعض السلوكيات الأخرى.

  3. يمكن للفئات تنفيذ أي عدد تريده من الواجهات، لكن يمكنها أن ترث فئة واحدة فقط.

    لقد ذكرنا هذا بالفعل أكثر من مرة. لا تحتوي Java على وراثة متعددة للفئات، ولكنها تدعم الوراثة المتعددة للواجهات. تتبع هذه النقطة جزئيًا النقطة السابقة: تربط الواجهة بين العديد من الفئات المختلفة التي غالبًا لا يوجد شيء مشترك بينها، بينما يتم إنشاء فئة مجردة لمجموعة من الفئات المرتبطة ارتباطًا وثيقًا. لذلك، فمن المنطقي أنه يمكنك وراثة فئة واحدة فقط من هذا القبيل. يصف الفصل المجرد العلاقة "is-a".

الواجهات القياسية: InputStream وOutputStream

لقد تناولنا بالفعل مختلف الفئات المسؤولة عن تدفقات الإدخال والإخراج. دعونا نعتبر InputStreamو OutputStream. بشكل عام، هذه ليست واجهات على الإطلاق، ولكنها فئات مجردة حقيقية تمامًا. الآن أنت تعرف ما يعنيه ذلك، لذلك سيكون العمل معهم أسهل بكثير :) InputStreamهي فئة مجردة مسؤولة عن إدخال البايت. لدى Java عدة فئات ترث 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 '. نقوم بإنشاء كائنين - a FileInputStreamو a BufferedInputStreamالذي "يغلفه". ثم نقرأ البايتات من الملف ونحولها إلى أحرف. ونفعل ذلك حتى ينتهي الملف. كما ترون، لا يوجد شيء معقد هنا. يمكنك نسخ هذا الرمز وتشغيله على ملف حقيقي على جهاز الكمبيوتر الخاص بك :) الفئة OutputStreamعبارة عن فئة مجردة تمثل دفق إخراج من البايتات. كما تعلم بالفعل، هذا هو عكس InputStream. وهي ليست مسؤولة عن قراءة البيانات من مكان ما، بل هي مسؤولة عن إرسال البيانات إلى مكان ما . مثلًا InputStream، توفر هذه الفئة المجردة لجميع أحفادها مجموعة من الأساليب الملائمة:
  • void close()يغلق دفق الإخراج.
  • void flush()مسح كافة المخازن المؤقتة للإخراج؛
  • abstract void write(int oneByte)يكتب بايت واحد إلى دفق الإخراج؛
  • void write(byte[] buffer)يكتب مصفوفة بايت إلى دفق الإخراج؛
  • void write(byte[] buffer, int offset, int count)يكتب نطاقًا من عدد البايتات من صفيف، بدءًا من موضع الإزاحة.
وهنا بعض من أحفاد الطبقة OutputStream:
  1. DataOutputStream. دفق إخراج يتضمن طرقًا لكتابة أنواع بيانات Java القياسية.

    فئة بسيطة جدًا لكتابة أنواع وسلاسل بيانات Java البدائية. من المحتمل أنك ستفهم الكود التالي حتى بدون شرح:

    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، فهذه معلومات كافية للتعارف الأول. هذا كل شيء! نأمل أن تفهم الاختلافات بين الواجهات والفصول المجردة وأن تكون جاهزًا للإجابة على أي سؤال، حتى الأسئلة الخادعة :) FileOutputStreamBuffreredInputStream
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION