java في - كيف يمكنني شرح الفرق بين فئة Interface و Abstract؟




هو الجافا (25)

Even I have faced the same question in multiple interviews and believe me it makes your time miserable to convince the interviewer. If I inherent all the answers from above then I need to add one more key point to make it more convincing and utilizing OO at its best

In case you are not planning any modification in the rules , for the subclass to be followed, for a long future, go for the interface, as you wont be able to modify in it and if you do so, you need to go for the changes in all the other sub classes, whereas, if you think, you want to reuse the functionality, set some rules and also make it open for modification , go for Abstract class.

Think in this way, you had used a consumable service or you had provided some code to world and You have a chance to modify something, suppose a security check And If I am being a consumer of the code and One morning after a update , I find all read marks in my Eclipse, entire application is down. So to prevent such nightmares, use Abstract over Interfaces

I think this might convince the Interviewer to a extent...Happy Interviews Ahead.

في إحدى المقابلات التي أجريتها ، طُلب إليَّ شرح الفرق بين فصل الطبقة وواجهة الملخص .

وهنا ردي:

تعتبر طرق واجهة Java مجردة ضمنيًا ولا يمكن أن يكون لها تطبيقات. يمكن للفئة التجريدية في Java أن تحتوي على طرز أمثلة تقوم بتنفيذ سلوك افتراضي.

تكون المتغيرات المعلنة في واجهة Java نهائية بشكل افتراضي. قد تحتوي فئة الملخص على متغيرات غير نهائية.

يكون أعضاء واجهة Java عامًا افتراضيًا. يمكن للفئة التجريدية لـ Java أن يكون لديها النكهات المعتادة لأعضاء الصف مثل الخصوصية والحماية ، إلخ.

يجب تنفيذ واجهة Java باستخدام الكلمة المفتاحية keys. يجب توسيع فئة الملخص المجفف باستخدام الكلمة "extends".

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

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

ومع ذلك ، لم يكن راض المقابلة ، وقال لي أن هذا الوصف يمثل " المعرفة كتاب ".

سألني عن استجابة أكثر عملية ، وشرح متى سأختار صفًا مجردة عبر واجهة ، باستخدام أمثلة عملية .

اين أخطأت؟


I do interviews for work and i would look unfavourably on your answer aswell (sorry but im very honest). It does sound like you've read about the difference and revised an answer but perhaps you have never used it in practice.

A good explanation as to why you would use each can be far better than having a precise explanation of the difference. Employers ultimatley want programers to do things not know them which can be hard to demonstrate in an interview. The answer you gave would be good if applying for a technical or documentation based job but not a developers role.

Best of luck with interviews in the future.

Also my answer to this question is more about interview technique rather than the technical material youve provided. Perhaps consider reading about it. https://workplace.stackexchange.com/ can be an excellent place for this sort of thing.


يبدو تفسيراتك لائقة ، لكن ربما يبدو أنك كنت تقرأها كلها من كتاب مدرسي؟ : - /

ما أزعجني أكثر هو ، ما مدى قوة مثالك؟ هل تضايقت لتضمين جميع الاختلافات تقريباً بين الملخصات والواجهات؟

أنا شخصياً ، أقترح هذا الرابط: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

للحصول على قائمة شاملة بالاختلافات ..

آمل أن يساعدك أنت وكل القراء الآخرين في مقابلاتهم المستقبلية


You choose Interface in Java to avoid the Diamond Problem in multiple inheritance .

If you want all of your methods to be implemented by your client you go for interface. It means you design the entire application at abstract.

You choose abstract class if you already know what is in common. For example Take an abstract class Car . At higher level you implement the common car methods like calculateRPM() . It is a common method and you let the client implement his own behavior like
calculateMaxSpeed() etc. Probably you would have explained by giving few real time examples which you have encountered in your day to day job.


The main difference what i have observed was that abstract class provides us with some common behaviour implemented already and subclasses only needs to implement specific functionality corresponding to them. where as for an interface will only specify what tasks needs to be done and no implementations will be given by interface. I can say it specifies the contract between itself and implemented classes.


hmm now the people are hungery practical approach, you are quite right but most of interviewer looks as per their current requirment and want a practical approach.

after finishing your answer you should jump on the example:

Abstract:

for example we have salary function which have some parametar common to all employee. then we can have a abstract class called CTC with partialy defined method body and it will got extends by all type of employee and get redeined as per their extra beefits. For common functonality.

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

جهة تعامل

interface in java allow to have interfcae functionality without extending that one and you have to be clear with the implementation of signature of functionality that you want to introduce in your application. it will force you to have definiton. For different functionality. public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

you can have such forced activity with abstract class too by defined methgos as a abstract one, now a class tha extends abstract class remin abstract one untill it override that abstract function.


Yes, your responses were technically correct but where you went wrong was not showing them you understand the upsides and downsides of choosing one over the other. Additionally, they were probably concerned/freaked out about compatibility of their codebase with upgrades in the future. This type of response may have helped (in addition to what you said):

"Choosing an Abstract Class over an Interface Class depends on what we project the future of the code will be.

Abstract classes allow better forward-compatibility because you can continue adding behavior to an Abstract Class well into the future without breaking your existing code --> this is not possible with an Interface Class.

On the other hand, Interface Classes are more flexible than Abstract Classes. This is because they can implement multiple interfaces . The thing is Java does not have multiple inheritances so using abstract classes won't let you use any other class hierarchy structure...

So, in the end a good general rule of thumb is: Prefer using Interface Classes when there are no existing/default implementations in your codebase. And, use Abstract Classes to preserve compatibility if you know you will be updating your class in the future."

Good luck on your next interview!


An interface is a "contract" where the class that implements the contract promises to implement the methods. An example where I had to write an interface instead of a class was when I was upgrading a game from 2D to 3D. I had to create an interface to share classes between the 2D and the 3D version of the game.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

Then I can implement the methods based on the environment, while still being able to call those methods from an object that doesn't know which version of the game that is loading.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Typically, in the gameworld, the world can be an abstract class that performs methods on the game:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

In abstract class, you can write default implementation of methods! But in Interface you can not. Basically, In interface there exist pure virtual methods which have to be implemented by the class which implements the interface.


تتكون الواجهة من متغيرات فردية (نهائية ثابتة عامة) وطرق تجريدية عامة. نفضل عادةً استخدام واجهة في الوقت الفعلي عندما نعرف ما يجب القيام به ولكن لا نعرف كيفية القيام به .

يمكن فهم هذا المفهوم بشكل أفضل من خلال المثال:

النظر في فئة الدفع. يمكن أن يتم الدفع بعدة طرق ، مثل PayPal ، وبطاقات الائتمان ، إلخ. لذلك فإننا نأخذ عادةً الدفع makePayment() التي تحتوي على طريقة makePayment() و CreditCard و PayPal هما makePayment() التنفيذ.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

في المثال أعلاه ، CreditCard و PayPal هما فئتان / استراتيجيات تنفيذ. واجهة تسمح لنا أيضا مفهوم الميراث متعددة في جاوة التي لا يمكن تحقيقها من خلال فئة مجردة.

نختار فئة مجردة عندما تكون هناك بعض الميزات التي نعرف ما يجب القيام به ، والميزات الأخرى التي نعرف كيفية القيام بها .

خذ بعين الاعتبار المثال التالي:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

إذا أضفنا أساليب (ملموسة / مجردة) في المستقبل إلى فئة مجردة معينة ، فلن تحتاج فئة التنفيذ إلى تغيير رمزها. ومع ذلك ، إذا قمنا بإضافة أساليب في واجهة في المستقبل ، يجب أن نضيف تطبيقات إلى جميع الفئات التي نفذت هذه الواجهة ، وإلا فإن أخطاء وقت الترجمة تحدث.

هناك اختلافات أخرى ، لكن هذه اختلافات رئيسية ربما كانت ما توقعه المحاور. نأمل أن هذا كان مفيدا.


لقد قدمت ملخصًا جيدًا للاختلافات العملية في الاستخدام والتطبيق ولكن لم تقل أي شيء عن الفرق في المعنى.

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

تعتبر الطبقة المجردة أساسًا للفئات الفرعية المختلفة التي تشترك في السلوك والتي لا يلزم إنشاؤها بشكل متكرر. يجب أن تستكمل الفئة الفرعية السلوك وأن يكون لديها خيار تجاوز السلوك المعرّف مسبقًا (طالما لم يتم تعريفه على أنه final أو private ).

سوف تجد أمثلة جيدة في حزمة java.util التي تتضمن واجهات مثل List وفئات مجردة مثل AbstractList التي تنفذ بالفعل واجهة. تصف الوثائق الرسمية the AbstractList النحو التالي:

توفر هذه الفئة تطبيقًا عظميًا لواجهة القائمة لتقليل الجهد المطلوب لتنفيذ هذه الواجهة المدعومة من مخزن بيانات "الوصول العشوائي" (مثل صفيف).


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

إن الواجهات والدروس المجردة ، رغم أنها متشابهة من الناحية الفنية ، لها معان وأغراض مختلفة تمامًا.

ملخص

  1. تحدد الواجهة عقدًا سيلبيه لك بعض التنفيذ.

  2. توفر فئة مجردة سلوك افتراضي يمكن إعادة استخدامه.

هاتان النقطتان أعلاه هي ما أبحث عنه عند إجراء المقابلة ، وهو موجز مدمج بما يكفي. اقرأ لتفاصيل أكثر.

ملخص بديل

  1. الواجهة هي لتعريف واجهات برمجة التطبيقات العامة
  2. الفئة التجريدية هي للاستخدام الداخلي ولتحديد SPIs

على سبيل المثال

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

من ناحية أخرى ، لا يهتم مستخدمو القائمة عالية المستوى بكيفية تنفيذها فعليًا ، ويجب عزلهم عن هذه التفاصيل. دعنا نتخيل أن جافا لم تعرض واجهة List ، ولكن كان لديها فقط طبقة List ملموسة في الواقع ما هو LinkedList الوقت الحالي. كان كل مطوري جافا قد صمموا الكود الخاص بهم ليتناسب مع تفاصيل التنفيذ: تجنب الوصول العشوائي ، أو إضافة ذاكرة تخزين مؤقت لتسريع الوصول ، أو إعادة إصدار ArrayList من تلقاء أنفسهم ، على الرغم من أنه سيكون غير متوافق مع كل الكودات الأخرى التي تعمل بالفعل مع List فقط. . سيكون ذلك رهيبًا ... ولكن الآن تخيل أن أساتذة جافا يدركون أن القائمة المرتبطة مرعبة جدًا لمعظم حالات الاستخدام الفعلية ، وقرروا الانتقال إلى قائمة مصفوفة لفئة القائمة الوحيدة المتاحة لهم. هذا من شأنه أن يؤثر على أداء كل برامج جافا في العالم ، ولن يكون الناس سعداء بذلك. والمصدر الرئيسي هو أن تفاصيل التنفيذ كانت متوفرة ، ويفترض المطورون أن تلك التفاصيل هي عقد دائم يمكنهم الاعتماد عليه. ولهذا السبب من المهم إخفاء تفاصيل التنفيذ ، وتحديد فقط عقدًا مجرّدًا. هذا هو الغرض من الواجهة: تحديد نوع المدخلات التي تقبلها الطريقة ، وأي نوع من المخرجات المتوقعة ، دون تعريض جميع الشجاعة التي من شأنها إغراء المبرمجين على تعديل كودهم لتتناسب مع التفاصيل الداخلية التي قد تتغير مع أي تحديث مستقبلي .

توجد فئة مجردة في الوسط بين السطوح البينية والطبقات الملموسة. من المفترض أن تساعد التطبيقات على مشاركة الشفرة الشائعة أو المملة. على سبيل المثال ، يوفر AbstractCollection تطبيقات أساسية لـ isEmpty استنادًا إلى الحجم هو 0 ، contains التكرار والمقارنة ، addAll مثل add المتكررة ، وهكذا. وهذا يتيح للتطبيقات التركيز على الأجزاء المهمة التي تفرق بينها: كيفية تخزين البيانات واستعادتها فعليًا.

منظور آخر: APIs مقابل SPIs

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

الفصول الدراسية Abstract هي مساعدين عالية التماسك لاستخدامها عند تنفيذ واجهة ، بافتراض مستوى معين من تفاصيل التنفيذ. بدلا من ذلك ، يتم استخدام فصول مجردة لتعريف SPIs ، واجهات مزود الخدمة.

يعتبر الاختلاف بين واجهة برمجة التطبيقات وواجهة SPI دقيقًا ، ولكنه مهم: بالنسبة إلى واجهة برمجة التطبيقات ، يكون التركيز على من يستخدمها ، وبالنسبة إلى SPI ، يكون التركيز على من ينفذها .

يعد إضافة طرق إلى واجهة برمجة التطبيقات أمرًا سهلاً ، وسيستمر تجميع جميع مستخدمي واجهة برمجة التطبيقات الحاليين. إن إضافة طرق إلى SPI أمر صعب ، حيث سيتعين على كل مزود خدمة (تنفيذ ملموس) تنفيذ الأساليب الجديدة. إذا تم استخدام الواجهات لتعريف SPI ، سيضطر الموفر إلى إصدار نسخة جديدة كلما تغير عقد SPI. إذا تم استخدام فصول مجردة بدلاً من ذلك ، فيمكن تحديد أساليب جديدة من حيث الأساليب المجردة الموجودة ، أو كعقبات throw not implemented exception الفارغة throw not implemented exception المطبقة ، والتي ستسمح على الأقل بنسخة قديمة من تنفيذ الخدمة حتى يتم تجميعها وتشغيلها.

ملاحظة على Java 8 والأساليب الافتراضية

Although Java 8 introduced default methods for interfaces, which makes the line between interfaces and abstract classes even blurrier, this wasn't so that implementations can reuse code, but to make it easier to change interfaces that serve both as an API and as an SPI (or are wrongly used for defining SPIs instead of abstract classes).

"Book knowledge"

The technical details provided in the OP's answer are considered "book knowledge" because this is usually the approach used in school and in most technology books about a language: what a thing is, not how to use it in practice, especially in large scale applications.

Here's an analogy: supposed the question was:

What is better to rent for prom night, a car or a hotel room?

The technical answer sounds like:

Well, in a car you can do it sooner, but in a hotel room you can do it more comfortably. On the other hand, the hotel room is in only one place, while in the car you can do it in more places, like, let's say you can go to the vista point for a nice view, or in a drive-in theater, or many other places, or even in more than one place. Also, the hotel room has a shower.

That is all true, but completely misses the points that they are two completely different things, and both can be used at the same time for different purposes, and the "doing it" aspect is not the most important thing about either of the two options. The answer lacks perspective, it shows an immature way of thinking, while correctly presenting true "facts".


سأقدم لك مثالاً أولاً:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

الآن افترض أن لديك 3 قواعد بيانات في التطبيق الخاص بك. ثم يحتاج كل تطبيق لقاعدة البيانات هذه إلى تحديد الطرق أعلاه 2:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

ولكن ماذا لو كانت encryptPassword () لا تعتمد على قاعدة البيانات ، وهي نفسها لكل فئة؟ ثم ما ورد أعلاه لن يكون نهجا جيدا.

بدلاً من ذلك ، ضع في اعتبارك هذا الأسلوب:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

الآن في كل فصل دراسي ، نحتاج فقط إلى تنفيذ طريقة واحدة - الطريقة التي تعتمد على قاعدة البيانات.

لقد حاولت جهدي وأتمنى أن يزيل هذا شكوكك.


Abstract classes are not pure abstraction bcz its collection of concrete(implemented methods) as well as unimplemented methods. But Interfaces are pure abstraction bcz there are only unimplemented methods not concrete methods.

Why Abstract classes?

  1. If user want write common functionality for all objects.
  2. Abstract classes are best choice for reimplementation in future that to add more functionality without affecting of end user.

Why Interfaces?

  1. If user want to write different functionality that would be different functionality on objects.
  2. Interfaces are best choice that if not need to modify the requirements once interface has been published.

What about thinking the following way:

  • A relationship between a class and an abstract class is of type "is-a"
  • A relationship between a class and an interface is of type "has-a"

So when you have an abstract class Mammals, a subclass Human, and an interface Driving, then you can say

  • each Human is-a Mammal
  • each Human has-a Driving (behavior)

My suggestion is that the book knowledge phrase indicates that he wanted to hear the semantic difference between both (like others here already suggested).



The main difference what i have observed was that abstract class provides us with some common behaviour implemented already and subclasses only needs to implement specific functionality corresponding to them. where as for an interface will only specify what tasks needs to be done and no implementations will be given by interface. I can say it specifies the contract between itself and implemented classes.


your answer is right but the interviewer needs you to differentiate according to software engineering perspective not according to the details of Java.

Simple words:

An Interface is like the interface of a shop anything that is shown on it should be there in the shop, so any method in the Interface must be there implemented in the concrete class. Now what if some classes share some exact methods and varies in others. Suppose the Interface is about a shop that contains two things and suppose we have two shops both contain sport equipment but one has clothes extra and the other has shoes extra. So what you do is making an abstract class for Sport that implements the Sports method and leave the other method unimplemented. Abstract class here means that this shop doesn't exist itself but it is the base for other classes/shops. This way you are organising the code, avoiding errors of replicating the code, unifying the code, and ensuring re-usability by some other class.


الفرق بين الطبقة Abstact والواجهة

  1. دروس الملخص مقابل الواجهات في Java 8
  2. الفرق المفاهيمي:

طرق الواجهة الافتراضية في Java 8

  1. ما هي الطريقة الافتراضية؟
  2. تم حل خطأ تجميع أسلوب ForEach باستخدام الطريقة الافتراضية
  3. الطريقة الافتراضية ومشاكل الغموض الوراثة المتعددة
  4. نقاط مهمة حول الطرق الافتراضية لواجهة جافا:

طريقة جافا واجهة ثابتة

  1. Java Interface Static Method ، مثال للشفرة ، طريقة ثابتة مقابل الطريقة الافتراضية
  2. نقاط مهمة حول طريقة ثابت واجهة java:

واجهات وظيفية جافا

دروس الملخص مقابل الواجهات في Java 8

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

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

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

الفرق المفاهيمي:

تعتبر الطبقات المجردة صالحة للتطبيقات الهيكلية (أي الجزئية) للواجهات ، ولكن لا ينبغي أن توجد بدون واجهة مطابقة.

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

طرق الواجهة الافتراضية في Java 8

تقدم Java 8 " الطريقة الافتراضية " أو (أساليب Defender) الجديدة ، والتي تسمح للمطور بإضافة أساليب جديدة إلى واجهات دون كسر التنفيذ الحالي لهذه الواجهة. ويوفر المرونة للسماح للواجهة بتعريف التطبيق الذي سيستخدم كإعداد افتراضي في الحالة التي تخفق فيها الطبقة الملموسة في توفير تنفيذ لتلك الطريقة.

لنأخذ مثالاً صغيرًا لفهم كيفية عمله:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

سيتم تجميع الفئة التالية بنجاح في Java 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(); 

الطريقة الافتراضية:

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

يمكن توفير الطرق الافتراضية لواجهة دون التأثير على تنفيذ الفئات لأنها تتضمن تنفيذًا. إذا كانت كل طريقة مضافة في واجهة معرفة بالتطبيق فلن تتأثر فئة المنفذ. يمكن أن تتجاوز فئة التنفيذ التنفيذ الافتراضي الذي توفره الواجهة.

تمكين الأساليب الافتراضية لإضافة وظائف جديدة إلى واجهات موجودة دون فصل تنفيذ الأقدم من هذه الواجهات.

عندما نقوم بتوسيع واجهة تحتوي على طريقة افتراضية ، يمكننا تنفيذ المتابعة ،

  1. لا تتخطى الطريقة الافتراضية وسوف ترث الطريقة الافتراضية.
  2. تجاوز الطريقة الافتراضية المشابهة للطرق الأخرى التي نتجاوزها في الفئة الفرعية.
  3. طريقة Redeclare الافتراضية كمفرد ، والتي تجبر الفئة الفرعية على تجاوزها.

تم حل خطأ تجميع أسلوب ForEach باستخدام الطريقة الافتراضية

بالنسبة لجافا 8 ، تم تمديد مجموعات JDK و يتم إضافة طريقة forEach إلى المجموعة بأكملها (التي تعمل بالاقتران مع lambdas). بالطريقة التقليدية ، يبدو الرمز أدناه ،

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);
        }
    }
}

تم استخدام نفس الآلية لإضافة Stream في واجهة JDK دون فصل فئات التنفيذ.

الطريقة الافتراضية ومشاكل الغموض الوراثة المتعددة

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

النظر في المثال أدناه ،

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 يرث الإعدادات الافتراضية غير المرتبطة بـ defaultMethod () من الأنواع InterfaceA و InterfaceB

لإصلاح هذا الفصل ، نحتاج إلى توفير طريقة تنفيذ افتراضية:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

علاوة على ذلك ، إذا أردنا استدعاء التنفيذ الافتراضي الذي توفره أي واجهة فائقة بدلاً من التنفيذ الخاص بنا ، فيمكننا القيام بذلك على النحو التالي ،

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

يمكننا اختيار أي تطبيق افتراضي أو كليهما كجزء من طريقتنا الجديدة.

نقاط مهمة حول الطرق الافتراضية لواجهة جافا:

  1. ستساعدنا الطرق الافتراضية لواجهة Java في توسيع الواجهات دون الخوف من كسر فصول التنفيذ.
  2. تحتوي الطرق الافتراضية لواجهة Java على جسر الاختلافات بين الواجهات والفئات المجردة.
  3. ستساعدنا الطرق الافتراضية لواجهة Java 8 في تجنب فئات الأداة المساعدة ، مثل كل طريقة فئات المجموعات التي يمكن توفيرها في الواجهات نفسها.
  4. ستساعدنا الطرق الافتراضية لواجهة Java في إزالة فئات التنفيذ الأساسية ، ويمكننا توفير التنفيذ الافتراضي ويمكن أن تختار فئات التنفيذ أيًا منها لتجاوزه.
  5. أحد الأسباب الرئيسية لإدخال الأساليب الافتراضية في الواجهات هو تحسين واجهة برمجة تطبيقات Collections في Java 8 لدعم تعبيرات lambda.
  6. إذا كان لأي فئة في التسلسل الهرمي طريقة لها نفس التوقيع ، فإن الطرق الافتراضية تصبح غير ذات صلة. لا يمكن للطريقة الافتراضية تجاوز طريقة من java.lang.Object. المنطق بسيط جداً ، لأن السبب هو الفئة الأساسية لجميع فئات جافا. لذلك حتى إذا كان لدينا أساليب فئة كائن المعرفة كطرق افتراضية في واجهات ، سيكون عديم الفائدة لأن دومًا سيتم استخدام أسلوب فئة الكائن. ولهذا السبب لتجنب الارتباك ، لا يمكننا استخدام الطرق الافتراضية التي تتجاوز أساليب فئة الكائن.
  7. يشار إلى الطرق الافتراضية لواجهة Java أيضًا باسم أساليب Defender أو طرق الإضافة الظاهرية.

رابط الموارد:

  1. واجهة مع الأساليب الافتراضية مقابل فئة الملخص في Java 8
  2. الطبقة التجريدية مقابل الواجهة في عصر JDK 8
  3. تطور واجهة عبر طرق الإمتداد الظاهري

طريقة جافا واجهة ثابتة

Java Interface Static Method ، مثال للشفرة ، طريقة ثابتة مقابل الطريقة الافتراضية

تشبه طريقة Java interface static الطريقة الافتراضية باستثناء أننا لا يمكننا تجاوزها في فئات التنفيذ. تساعدنا هذه الميزة في تجنب النتائج غير المرغوبة في حالة ضعف التنفيذ في فصول التنفيذ. دعونا ننظر في هذا مع مثال بسيط.

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;
    }
}

الآن دعنا نرى فصل تطبيق موجود هو isNull () بطريقة التنفيذ الضعيف.

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");
    }
}

لاحظ أن isNull (String str) عبارة عن طريقة بسيطة للفئة ، وهي لا تتجاوز أسلوب الواجهة. على سبيل المثال ، إذا قمنا بإضافة تعليق توضيحي لـOverride إلى طريقة isNull () ، فسوف ينتج عنه خطأ المحول البرمجي.

الآن عندما سنقوم بتشغيل التطبيق ، نأتي بعد الإخراج.

واجهة فحص الشيكات

Impl Null Check

إذا قمنا بعمل أسلوب الواجهة من ثابت إلى افتراضي ، فسوف نتتبع الإخراج.

Impl Null Check

MyData طباعة ::

Impl Null Check

طريقة Java interface static مرئية لأساليب الواجهة فقط ، إذا قمنا بإزالة الأسلوب isNull () من فئة MyDataImpl ، فلن نتمكن من استخدامه لكائن MyDataImpl. ومع ذلك ، مثل الأساليب الثابتة الأخرى ، يمكننا استخدام أساليب ثابتة للواجهة باستخدام اسم الفئة. على سبيل المثال ، سيكون بيان صالح هو:

boolean result = MyData.isNull("abc");

نقاط مهمة حول طريقة ثابت واجهة java:

  1. طريقة جافا واجهة ثابتة هي جزء من واجهة ، لا يمكننا استخدامه لكائنات فئة التنفيذ.
  2. تعتبر الطرق الساكنة لواجهة Java مفيدة في توفير وسائل المرافق ، على سبيل المثال ، الفحص الفارغ ، وجمع العينات وما إلى ذلك.
  3. تساعد طريقة Java interface static في توفير الأمان من خلال عدم السماح لفئات التنفيذ بتجاوزها.
  4. لا يمكننا تعريف طريقة ثابتة للواجهة لطرق فئة كائن ، سنحصل على خطأ في المحول البرمجي كـ "لا تستطيع هذه الطريقة الثابتة إخفاء أسلوب المثيل من الكائن". هذا لأنه غير مسموح به في java ، حيث أن Object هو الفئة الأساسية لجميع الفئات ، ولا يمكن أن نحصل على طريقة ثابتة واحدة على مستوى الفصل وطريقة مثيل أخرى لها نفس التوقيع.
  5. يمكننا استخدام أساليب ثابتة واجهة java لإزالة فئات الأداة المساعدة مثل مجموعات ونقل كل من الأساليب الثابتة إلى الواجهة المناظرة ، التي من السهل العثور عليها واستخدامها.

واجهات وظيفية جافا

قبل أن أختتم المنشور ، أود تقديم مقدمة موجزة للواجهات الوظيفية. تعرف الواجهة مع طريقة مجردة واحدة تمامًا باسم الواجهة الوظيفية.

تم تقديم شرح توضيحي جديد @FunctionalInterface لتمييز واجهة كـ Functional Interface. @FunctionalInterface التعليق @FunctionalInterface عبارة عن وسيلة لتجنب الإضافة غير المقصودة للطرق المجردة في الواجهات الوظيفية. إنها ممارسة اختيارية ولكن جيدة لاستخدامها.

تعتبر الواجهات الوظيفية التي طال انتظارها ميزة كبيرة في Java 8 ، لأنها تمكننا من استخدام تعبيرات lambda لتفعيلها. يتم إضافة حزمة java.util.function جديدة مع مجموعة من واجهات وظيفية لتوفير أنواع الهدف لمفردات lambda ومراجع الأسلوب. سننظر في واجهات وظيفية وتعابير لامدا في الوظائف المستقبلية.

موقع الموارد:

  1. Java 8 Interface Changes - static method، default method

When I am trying to share behavior between 2 closely related classes, I create an abstract class that holds the common behavior and serves as a parent to both classes.

When I am trying to define a Type, a list of methods that a user of my object can reliably call upon, then I create an interface.

For example, I would never create an abstract class with 1 concrete subclass because abstract classes are about sharing behavior. But I might very well create an interface with only one implementation. The user of my code won't know that there is only one implementation. Indeed, in a future release there may be several implementations, all of which are subclasses of some new abstract class that didn't even exist when I created the interface.

That might have seemed a bit too bookish too (though I have never seen it put that way anywhere that I recall). If the interviewer (or the OP) really wanted more of my personal experience on that, I would have been ready with anecdotes of an interface has evolved out of necessity and visa versa.

One more thing. Java 8 now allows you to put default code into an interface, further blurring the line between interfaces and abstract classes. But from what I have seen, that feature is overused even by the makers of the Java core libraries. That feature was added, and rightly so, to make it possible to extend an interface without creating binary incompatibility. But if you are making a brand new Type by defining an interface, then the interface should be JUST an interface. If you want to also provide common code, then by all means make a helper class (abstract or concrete). Don't be cluttering your interface from the start with functionality that you may want to change.


I believe what the interviewer was trying to get at was probably the difference between interface and implementation.

The interface - not a Java interface, but "interface" in more general terms - to a code module is, basically, the contract made with client code that uses the interface.

The implementation of a code module is the internal code that makes the module work. Often you can implement a particular interface in more than one different way, and even change the implementation without client code even being aware of the change.

A Java interface should only be used as an interface in the above generic sense, to define how the class behaves for the benefit of client code using the class, without specifying any implementation. Thus, an interface includes method signatures - the names, return types, and argument lists - for methods expected to be called by client code, and in principle should have plenty of Javadoc for each method describing what that method does. The most compelling reason for using an interface is if you plan to have multiple different implementations of the interface, perhaps selecting an implementation depending on deployment configuration.

A Java abstract class, in contrast, provides a partial implementation of the class, rather than having a primary purpose of specifying an interface. It should be used when multiple classes share code, but when the subclasses are also expected to provide part of the implementation. This permits the shared code to appear in only one place - the abstract class - while making it clear that parts of the implementation are not present in the abstract class and are expected to be provided by subclasses.


From what I understand and how I approach,

Interface is like a specification/contract, any class that implements a interface class have to implement all the methods defined in the abstract class (except default methods (introduced in java 8))

Whereas I define a class abstract when I know the implementation required for some methods of the class and some methods I still do not know what will be the implementation(we might know the function signature but not the implementation). I do this so that later in the part of development when i know how these methods are to be implemented, i can just extend this abstract class and implement these methods.

Note: You cannot have function body in interface methods unless the method is static or default.


An interface is like a set of genes that are publicly documented to have some kind of effect: A DNA test will tell me whether I've got them - and if I do, I can publicly make it known that I'm a "carrier" and part of my behavior or state will conform to them. (But of course, I may have many other genes that provide traits outside this scope.)

An abstract class is like the dead ancestor of a single-sex species (*): She can't be brought to life but a living (ie non-abstract ) descendant inherits all her genes.

(*) To stretch this metaphor, let's say all members of the species live to the same age. This means all ancestors of a dead ancestor must also be dead - and likewise, all descendants of a living ancestor must be alive.


I will try to answer using practical scenario to show the distinction between the two.

Interfaces come with zero payload ie no state has to be maintained and thus are better choice to just associate a contract (capability) with a class.

For example, say I have a Task class that performs some action, now to execute a task in separate thread I don't really need to extend Thread class rather better choice is to make Task implement Runnable interface (ie implement its run() method) and then pass object of this Task class to a Thread instance and call its start() method.

Now you can ask what if Runnable was a abstract class?

Well technically that was possible but design wise that would have been a poor choice reason being:

  • Runnable has no state associated with it and neither it 'offers' any default implementation for the run() method
  • Task would have to extend it thus it couldn't extend any other class
  • Task has nothing to offer as specialization to Runnable class, all it needs is to override run() method

In other words, Task class needed a capability to be run in a thread which it achieved by implementing Runnable interface verses extending the Thread class that would make it a thread.

Simply put us interface to define a capability (contract), while use a abstract class to define skeleton (common/partial) implementation of it.

Disclaimer: silly example follows, try not to judge :-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

Now you have been given a choice to be GodLike but you may choose to be Forgiver only (ie not GodLike) and do:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Or you may may choose to be GodLike and do:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

PS with java 8 interface can also have static as well default (overridable implementation) methods and thus difference b/w interface and abstract class is even more narrowed down.


قد يكون البرنامج التعليمي الرسمي من بعض الاستخدام لك.

            │ Class │ Package │ Subclass │ Subclass │ World
            │       │         │(same pkg)│(diff pkg)│ 
────────────┼───────┼─────────┼──────────┼──────────┼────────
public      │   +   │    +    │    +     │     +    │   +     
────────────┼───────┼─────────┼──────────┼──────────┼────────
protected   │   +   │    +    │    +     │     +    │         
────────────┼───────┼─────────┼──────────┼──────────┼────────
no modifier │   +   │    +    │    +     │          │    
────────────┼───────┼─────────┼──────────┼──────────┼────────
private     │   +   │         │          │          │    

+ : accessible
blank : not accessible




java oop inheritance interface abstract-class