Як я повинен пояснити різницю між класом інтерфейсу та абстрактним?


469

В одному зі своїх інтерв'ю мене попросили пояснити різницю між інтерфейсом та абстрактним класом .

Ось моя відповідь:

Методи інтерфейсу Java неявно абстрактні і не можуть мати реалізації. Абстрактний клас Java може мати методи екземпляра, які реалізують поведінку за замовчуванням.

Змінні, оголошені в інтерфейсі Java, за замовчуванням є остаточними. Абстрактний клас може містити не остаточні змінні.

Члени інтерфейсу Java за замовчуванням є загальнодоступними. Абстрактний клас Java може мати звичайні смаки для членів класу, як приватні, захищені тощо.

Інтерфейс Java повинен бути реалізований за допомогою ключового слова "tools"; Абстрактний клас Java слід розширити за допомогою ключового слова "extends".

Інтерфейс може розширювати лише інший Java-інтерфейс, абстрактний клас може розширювати інший клас Java та реалізовувати декілька Java-інтерфейсів.

Клас Java може реалізовувати декілька інтерфейсів, але він може розширювати лише один абстрактний клас.

Однак інтерв'юер не був задоволений, і сказав мені, що цей опис представляє " книжкові знання ".

Він попросив мене більш практичної відповіді, пояснивши, коли я оберу абстрактний клас через інтерфейс, використовуючи практичні приклади .

Де я помилився?


32
Можливо, ваша відповідь виглядала так, що ви говорите щось, чого не розумієте? Можливо, вам просто потрібно змінити стиль розповіді на той, який більше схожий на власні слова.
Кирило Кобелєв

19
Ви відповіли переліком (цілком правильних) технічних відмінностей. Інтерв'юер, швидше за все, шукав більш концептуальну відповідь (наприклад, на якій основі вибрати один інтерфейс та абстрактний клас).
Тед Хопп

15
Ви забули сказати, що абстрактні класи мають конструктори, навіть якщо ви не можете створити абстрактний клас, const. використовується в дитячих класах. Інтерфейси вказують "що", але не "як", оскільки вони визначають контракт (перелік методів) під час відсутності. клас може також вказати "як" (реалізувати мет.). Використання int. ви можете імітувати кілька успадкованих (клас може реалізувати кілька int., але лише розширити один клас). Використання int. ви можете мати базовий тип для dif. родини: Flyer f = нова площина (); Flyer f2 = нова Bird (); Птах і літак не відповідають одній родині, але обидва можуть літати (є листівками).
Francisco Francisco Goldenstein

7
Як і інтерфейси java8, можуть містити методи. Тому поза концепцією OO ці так звані "відмінності" можуть змінюватися в будь-який день
носія кільця

15
У мене немає жодної проблеми з вашою відповіддю, і я не думаю, що інтерв'юер має якусь справу, щоб насміхатися над «книжковими знаннями». Інтерв'юери не завжди знають правильних відповідей на запитання, які вони задають, а деякі інтерв'ю служать лише попередженням про те, щоб не працювати там.
Маркіз Лорн

Відповіді:


513

Я наведу вам перший приклад:

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

Припустимо, у вашій програмі є 3 бази даних. Тоді для кожної реалізації цієї бази даних необхідно визначити два вищевказані методи:

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

Тепер у кожному дочірньому класі нам потрібно реалізувати лише один метод - метод, залежний від бази даних.


97
Я не впевнений, що це дійсно пояснює різницю ... впевнений, що це приємна техніка. Я вважаю, що також варто зазначити, що Java 8 нарешті визнала, що C ++ був правильним і що може бути здійснено багатократне успадкування і може використовуватись, тому інтерфейси тепер можуть визначати не лише підписи функцій, але й забезпечувати реалізацію за замовчуванням. Таким чином, використання інтерфейсу було б кращим.
thecoshman

1
@thecoshman Яка різниця мала б, якби я підійшов до питання, як у відповіді (абстрактний клас із одним реалізованим методом та іншим абстрактним) або визначив інтерфейс із реалізацією методу за замовчуванням? В основному, я намагаюся сказати, що ви написали, що "використання інтерфейсу було б кращим", і моє питання - чому?
Нейтрино

1
Тож, я думаю, справедливо сказати тоді, що за допомогою інтерфейсів реалізація визначеного залежить від класу, який реально реалізує інтерфейс, тоді як речі в абстрактному класі є "ядром" для класів, що розширюють клас; тобто вона не змінюється.
orrymr

4
@Neutrino Незважаючи на те, що Java дозволяє реалізовувати декілька інтерфейсів, кожен з яких пропонує виконання за замовчуванням для функцій, ви все одно можете розширити лише один клас. Таким чином, використання інтерфейсу може забезпечити більшу гнучкість для тих, хто хоче ним користуватися разом з іншими інтерфейсами.
thecoshman

3
@HiradNikoo Вибачте за пізній коментар, але я просто натрапив на цю тему. Ви також можете вважати успадкування класів відносинами IS-A, тоді як інтерфейси означають, що "має певну функціональність".
Олександр Янк

206

У цьому світі нічого ідеального. Вони, можливо, очікували більше практичного підходу.

Але після вашого пояснення ви можете додати ці рядки дещо іншим підходом.

  1. Інтерфейси - це правила (правила, тому що ви повинні дати їм реалізацію, яку ви не можете ігнорувати чи уникати, щоб вони нав'язувалися як правила), що працює як загальнодоступний документ між різними командами в розробці програмного забезпечення.

  2. Інтерфейси дають уявлення про те, що робити, але не як це буде зроблено. Тож реалізація повністю залежить від розробника, дотримуючись заданих правил (означає дану підпис методів).

  3. Абстрактні класи можуть містити абстрактні декларації, конкретні реалізації або те і інше.

  4. Абстрактні декларації - це як правила, яких слід дотримуватися, а конкретні реалізації - як керівні принципи (ви можете використовувати його таким, яким він є, або ви можете ігнорувати його, переосмислюючи та надаючи йому власну реалізацію).

  5. Більше того, які методи з однаковою підписом можуть змінити поведінку в іншому контексті, надаються як оголошення інтерфейсу як правила для відповідної реалізації в різних контекстах.

Правка: Java 8 полегшує визначення стандартних та статичних методів в інтерфейсі.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

Тепер, коли клас реалізує SomeInterface, не обов’язково забезпечувати реалізацію для методів інтерфейсу за замовчуванням.

Якщо у нас є інший інтерфейс із наступними методами:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java не дозволяє розширювати декілька класів, оскільки це призводить до "Diamond Problem", де компілятор не може вирішити, який метод надкласового класу використовувати. З методами за замовчуванням проблема алмазів виникне і для інтерфейсів. Тому що якщо клас реалізує і те, і інше

SomeInterfaceOne and SomeInterfaceTwo

і не реалізує загальний метод за замовчуванням, компілятор не може визначити, який вибрати. Щоб уникнути цієї проблеми, в java 8 обов'язково потрібно застосовувати загальні методи за замовчуванням різних інтерфейсів. Якщо будь-який клас реалізує обидва вищевказані інтерфейси, він повинен забезпечити реалізацію методу defaultMethod (), інакше компілятор видасть помилку часу компіляції.


11
+1, це справді хороша відповідь, щоб уникнути плутанини. Але я не бачив жодного посилання і не знаю, чому ви цитували ці цінні рядки. Поставте їх, якщо це можливо :).
Суреш Атта

Прочитайте мій коментар вище про емуляцію множинного успадкування за допомогою інтерфейсів та використання інтерфейсів для базового типу для класів різних сімей. Я думаю, що інтерв'юер хоче почути такі відповіді від опитаних.
Франсіско Голденштейн

Ваш коментар також вказує на хороший приклад використання інтерфейсу. Я написав, що відчуваю, працюючи день у день. Ці слова можуть бути не професійними або точними. Але це те, про що я дізнався після тісної роботи з абстрактними класами та інтерфейсами в своєму щоденному кодуванні.
Шайлеш Саксена

4. Конкретними реалізаціями є також правила, що мають реалізацію за замовчуванням.
Лютен

@Luten: Згідно з моїми знаннями, якщо ви можете без проблем уникнути / проігнорувати правило, це повинно бути правилом, а не правилом. Будь ласка, виправте мене, якщо я помиляюся.
Шайлеш Саксена

168

Ви склали хороший підсумок практичних відмінностей у використанні та реалізації, але нічого не сказали про різницю в значенні.

Інтерфейс є описом поведінки виконавця класу матиме. Клас реалізації гарантує, що він буде мати ці методи, які можуть бути використані на ньому. Це в основному контракт або обіцянка, яку повинен дати клас.

Абстрактний клас є основою для різних підкласів , що поведінка акцій , які не повинні бути повторно створені. Підкласи повинні завершувати поведінку і мати можливість змінити заздалегідь задану поведінку (до тих пір, поки вона не буде визначена як finalабо private).

Ви знайдете хороші приклади в java.utilпакеті, який включає в себе інтерфейси на зразок Listта абстрактні класи, такі як AbstractListуже реалізований інтерфейс. В офіційній документації описано AbstractListнаступне:

Цей клас забезпечує скелетну реалізацію інтерфейсу List, щоб мінімізувати зусилля, необхідні для реалізації цього інтерфейсу, підкріпленого сховищем даних "випадкового доступу" (наприклад, масивом).


16
Це має бути відповіддю. Не перелік деталей, а основна концепція, яка відрізняє інтерфейс та абстрактний клас не лише на Java, але й загалом.
edc65

1
Це справді добре. Звичайно, і інші відповіді хороші. Але це говорить вам про головне підключення до abstractключових слів, тобто коли компілятор бачить це, вони знають, що наступна інформація є неповною і потребує впровадження . Інтерфейси завжди неповні, але абстрактні класи абстрактні, оскільки вони повинні були мати incomplete (abstract)методи.
Ракіб

85

Інтерфейс складається з однотонних змінних (публічний статичний фінал) та публічних абстрактних методів. Ми зазвичай вважаємо за краще використовувати інтерфейс у режимі реального часу, коли ми знаємо, що робити, але не знаємо, як це зробити .

Цю концепцію можна зрозуміти на прикладі:

Розглянемо клас оплати. Оплата може здійснюватися різними способами, такими як PayPal, кредитна картка тощо. Тому ми зазвичай приймаємо Payment як наш інтерфейс, який містить makePayment()метод, а CreditCard і PayPal - два класи реалізації.

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 - це два класи / стратегії впровадження. Інтерфейс також дозволяє нам поняття множинного успадкування на Java, яке неможливо виконати абстрактним класом.

Ми вибираємо абстрактний клас, коли є деякі функції, для яких ми знаємо, що робити, та інші функції, які ми знаємо, як виконати .

Розглянемо наступний приклад:

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

Якщо ми в майбутньому додамо методи (конкретні / абстрактні) до даного абстрактного класу, тоді клас реалізації не потребує зміни свого коду. Однак, якщо ми в майбутньому додамо методи в інтерфейс, ми повинні додати реалізації до всіх класів, які реалізували цей інтерфейс, інакше трапляються помилки компіляції часу.

Є й інші відмінності, але це основні, які, можливо, були те, що очікував ваш інтерв'юер. Сподіваємось, це було корисно.


1
Ну, ця відповідь має багато сенсу, і це цілком зрозуміло на прикладі, коли ми вибираємо між interfaceі abstract class.
MAC

"що робити, але не знаю, як це зробити", оскільки ми визначаємо метод, не здійснюючи в ньому жодної реалізації "void makePayment ();", визначаючи при цьому реалізацію методу в класі, який реалізує інтерфейс.
Абдель-Рауф

45

Різниця між класом Abstact та інтерфейсом

  1. Абстрактні класи проти інтерфейсів на Java 8
  2. Концептуальна різниця:

Методи інтерфейсу за замовчуванням на Java 8

  1. Що таке метод за замовчуванням?
  2. Помилка компіляції методу ForEach вирішена за допомогою методу за замовчуванням
  3. Метод за замовчуванням і багатозначні проблеми з неоднозначністю успадкування
  4. Важливі моменти щодо стандартних методів інтерфейсу Java:

Статичний метод інтерфейсу Java

  1. Статичний метод інтерфейсу Java, приклад коду, статичний метод проти метод за замовчуванням
  2. Важливі моменти статичного методу інтерфейсу Java:

Функціональні інтерфейси 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. Перевизначити метод за замовчуванням як абстрактний, який змушує підклас переосмислювати його.

Помилка компіляції методу ForEach вирішена за допомогою методу за замовчуванням

Для Java 8 колекції JDK були розширені, і до всієї колекції додається метод forEach (які працюють в поєднанні з лямбдами). Звичайним способом код виглядає нижче,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

Оскільки це результат кожного класу реалізації з помилками компіляції, таким чином, додається метод за замовчуванням з необхідною реалізацією для того, щоб існуюча реалізація не повинна бути змінена.

Інтерактивний інтерфейс із методом за замовчуванням знаходиться нижче,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Цей же механізм був використаний для додавання потоку в інтерфейс JDK, не порушуючи класи реалізації.


Метод за замовчуванням і багатозначні проблеми з неоднозначністю успадкування

Оскільки java Class може реалізувати декілька інтерфейсів, і кожен інтерфейс може визначити метод за замовчуванням з однаковим підписом методу, отже, успадковані методи можуть конфліктувати один з одним.

Розглянемо нижче приклад,

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: клас 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();
    }
}

Ми можемо вибрати будь-яку реалізацію за замовчуванням або обидві як частину нашого нового методу.

Важливі моменти щодо стандартних методів інтерфейсу Java:

  1. Методи за замовчуванням інтерфейсу Java допоможуть нам розширити інтерфейси, не боячись порушити класи реалізації.
  2. Методи за замовчуванням інтерфейсу Java дозволяють зменшити відмінності між інтерфейсами та абстрактними класами.
  3. Методи за замовчуванням інтерфейсу Java 8 допоможуть нам уникнути класів утиліти, наприклад, всі методи класу Collections можуть бути надані в самих інтерфейсах.
  4. Методи за замовчуванням інтерфейсу Java допоможуть нам у видаленні базових класів реалізації, ми можемо забезпечити реалізацію за замовчуванням, а класи реалізації можуть вибрати, який з них переотримати.
  5. Однією з головних причин введення методів за замовчуванням в інтерфейси є вдосконалення API Collections в Java 8 для підтримки лямбда-виразів.
  6. Якщо будь-який клас в ієрархії має метод з однаковою підписом, то методи за замовчуванням стають неактуальними. Метод за замовчуванням не може замінити метод з java.lang.Object. Міркування дуже просте, тому що Object є базовим класом для всіх класів java. Тож навіть якщо у нас інтерфейси методів класу Object визначені як методи за замовчуванням в інтерфейсах, вони будуть марні, оскільки завжди буде використовуватися метод класу Object. Тому, щоб уникнути плутанини, у нас не може бути методів за замовчуванням, які переважають методи класу Object.
  7. Методи за замовчуванням інтерфейсу Java також називаються методами Defender або методами віртуального розширення.

Посилання на ресурс:

  1. Інтерфейс із методами за замовчуванням та класом Анотація на Java 8
  2. Абстрактний клас проти інтерфейсу в епоху JDK 8
  3. Еволюція інтерфейсу за допомогою методів віртуального розширення

Статичний метод інтерфейсу Java

Статичний метод інтерфейсу Java, приклад коду, статичний метод проти метод за замовчуванням

Статичний метод інтерфейсу Java схожий на метод за замовчуванням, за винятком того, що ми не можемо їх замінити в класах реалізації. Ця функція допомагає нам уникнути небажаних результатів у разі поганої реалізації у класах впровадження. Давайте розглянемо це на простому прикладі.

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 видимий лише для методів інтерфейсу, якщо ми видалимо метод isNull () з класу MyDataImpl, ми не зможемо використовувати його для об’єкта MyDataImpl. Однак, як і інші статичні методи, ми можемо використовувати статичні методи інтерфейсу за допомогою назви класу. Наприклад, дійсною заявою буде:

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

Важливі моменти статичного методу інтерфейсу Java:

  1. Статичний метод інтерфейсу Java є частиною інтерфейсу, ми не можемо використовувати його для об’єктів класу реалізації.
  2. Статичні методи інтерфейсу Java хороші для надання корисних методів, наприклад, перевірки нуля, сортування колекції тощо.
  3. Статичний метод інтерфейсу Java допомагає нам у забезпеченні безпеки, не дозволяючи класам впровадження їх замінювати.
  4. Ми не можемо визначити статичний метод інтерфейсу для методів класу Object, ми отримаємо помилку компілятора як "Цей статичний метод не може приховати метод примірника від Object". Це тому, що в Java не дозволено, оскільки Object є базовим класом для всіх класів, і ми не можемо стати статичним методом рівня одного класу та іншим методом екземпляра з однаковою підписом.
  5. Ми можемо використовувати статичні методи інтерфейсу Java для видалення класів утиліт, таких як Collections, і перемістити всі його статичні методи у відповідний інтерфейс, який було б легко знайти та використовувати.

Функціональні інтерфейси Java

Перш ніж я закінчу повідомлення, я хотів би коротко ознайомитись з функціональними інтерфейсами. Інтерфейс з точно одним абстрактним методом відомий як функціональний інтерфейс.

@FunctionalInterfaceБуло введено нову примітку для позначення інтерфейсу як функціонального інтерфейсу. @FunctionalInterfaceанотація - це можливість уникнути випадкового додавання абстрактних методів у функціональні інтерфейси. Це необов’язково, але хороша практика використовувати його.

Функціональні інтерфейси довгоочікувані і дуже затребувані особливості Java 8, оскільки це дозволяє нам використовувати лямбда-вирази для їх інстанції. Новий пакет java.util.function з купою функціональних інтерфейсів додається для забезпечення цільових типів лямбда-виразів та посилань на методи. Ми розглянемо функціональні інтерфейси та лямбда-вирази в майбутніх публікаціях.

Розташування ресурсу:

  1. Зміни інтерфейсу Java 8 - статичний метод, метод за замовчуванням

8
Я саме шукаю ці типи оновлених відповідей. Дякуємо за швидку відповідь.
Равіндра бабу

41

Усі ваші твердження дійсні, крім вашого першого твердження (після випуску Java 8):

Методи інтерфейсу Java неявно абстрактні і не можуть мати реалізації

На сторінці документації :

Інтерфейс - це еталонний тип, подібний до класу, який може містити лише константи, підписи методів, методи за замовчуванням, статичні методи та вкладені типи

Тіла методів існують лише для стандартних методів та статичних методів.

Методи за замовчуванням:

Інтерфейс може мати методи за замовчуванням , але відрізняються від абстрактних методів у абстрактних класах.

Методи за замовчуванням дозволяють додавати нові функціональні можливості в інтерфейси ваших бібліотек та забезпечувати бінарну сумісність з кодом, написаним для старих версій цих інтерфейсів.

Розширюючи інтерфейс, який містить метод за замовчуванням, ви можете зробити наступне:

  1. Не згадуйте про метод за замовчуванням взагалі, який дозволяє розширеному інтерфейсу успадкувати метод за замовчуванням.
  2. Перевизначити метод за замовчуванням, що робить його abstract.
  3. Перевизначте метод за замовчуванням, який його перекриває.

Статичні методи:

Крім методів за замовчуванням, ви можете визначити статичні методи в інтерфейсах. (Статичний метод - це метод, який асоціюється з класом, у якому він визначений, а не з будь-яким об'єктом. Кожен екземпляр класу ділиться своїми статичними методами.)

Це полегшує вам організацію допоміжних методів у ваших бібліотеках;

Приклад коду на сторінці документації про interfaceнаявність staticта defaultметоди.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Використовуйте наведені нижче вказівки, щоб вибрати, чи використовувати інтерфейс чи абстрактний клас.

Інтерфейс:

  1. Для визначення контракту (бажано без громадянства - я маю на увазі відсутні змінні)
  2. Для того, щоб зв'язати незв'язані класи мають можливості.
  3. Декларувати загальнодоступні постійні змінні ( незмінний стан )

Реферат:

  1. Поділіться кодом між декількома тісно пов'язаними класами. Це встановлює - це відношення.

  2. Поділитися загальним станом серед споріднених класів (стан можна змінити в конкретних класах)

Схожі повідомлення:

Інтерфейс проти абстрактного класу (загальний OO)

Реалізація проти розширень: Коли користуватися? Яка різниця?

Пройшовши ці приклади, ви можете це зрозуміти

Неспоріднені класи можуть мати можливості через інтерфейс, але пов'язані класи змінюють поведінку через розширення базових класів.


Що ви маєте на увазі, коли говорите "договір без громадянства"? Це пункт 1 про інтерфейси
Максим Дмитрієв

1
Відсутність змінного стану. Оскільки в інтерфейсі можуть бути константи, дані можуть бути мутовані на відміну від абстрактних класів
Равіндра бабу

1
Виправлення наведеного вище твердження. В інтерфейсі дані не можна мутувати на відміну від абстрактного класу
Равіндра, бабу

2
це найкраща відповідь. Він не тільки звертається до Java8, але також пояснює, в яких конкретних ситуаціях ви б використовували будь-яку.
Shuklaswag

Концепція statelessінтерфейсу є приємним хітом. Інтерфейс не може мати будь-якого стану (Інтерфейс може мати константи, але вони остаточні / статичні, тому незмінні).
Kaihua

22

Ваше пояснення виглядає пристойно, але може це виглядало так, ніби ви читали це все з підручника? : - /

Що мене більше турбує, наскільки твердим був твій приклад? Ви турбувались включати майже всі відмінності між абстрактними та інтерфейсами?

Особисто я б запропонував це посилання: http://mindprod.com/jgloss/interfacevsab абстракт.html#TABLE

для вичерпного переліку відмінностей ..

Сподіваємось, це допоможе вам та всім читачам у майбутніх інтерв’ю


1
Посилання поділяється справді приголомшливим
Premraj

Ви можете забезпечити реалізацію за замовчуванням в інтерфейсах Java, використовуючи ключове слово за замовчуванням
1616 року

21

Багато молодших розробників роблять помилку, вважаючи інтерфейси, абстрактні та конкретні класи незначними варіаціями одного і того ж, і вибирають один із них виключно з технічних причин: чи потрібно багатократне успадкування? Чи потрібно мені десь помістити загальні методи? Чи потрібно морочитися чимось, крім простого конкретного класу? Це неправильно, і в цих питаннях прихована головна проблема: "Я" . Коли ви пишете код для себе, ви рідко думаєте про інших теперішніх чи майбутніх розробників, які працюють над вашим кодом або з ним.

Інтерфейси та абстрактні класи, хоча й зовні схожі з технічної точки зору, мають абсолютно різні значення та призначення.

Підсумок

  1. Інтерфейс визначає контракт, який вам виконає деяка реалізація .

  2. Абстрактний клас забезпечує поведінку за замовчуванням, яку ваша реалізація може повторно використовувати.

Ці два пункти вище - це те, що я шукаю під час співбесіди, і є досить компактним резюме. Детальніше читайте далі.

Альтернативний підсумок

  1. Інтерфейс призначений для визначення загальнодоступних API
  2. Абстрактний клас призначений як для внутрішнього використання, так і для визначення SPI

На прикладі

Якщо говорити інакше: конкретний клас виконує фактичну роботу дуже конкретно. Наприклад, ArrayListвикористовує суміжну область пам’яті для компактного зберігання списку об’єктів, яка пропонує швидкий випадковий доступ, ітерацію та зміни на місці, але жахлива при вставках, видаленнях та інколи навіть доповненнях; тим часом, aLinkedListвикористовує подвійні зв’язані вузли для зберігання списку об’єктів, який натомість пропонує швидку ітерацію, зміни на місці та вставлення / видалення / додавання, але є жахливим при випадковому доступі. Ці два типи списків оптимізовані для різних випадків використання, і дуже важливо, як ви їх будете використовувати. Коли ви намагаєтесь вичавити продуктивність зі списку, з яким сильно взаємодієте, і коли вибираєте тип списку, вам слід ретельно вибрати, який саме ви будете отримувати.

З іншого боку, користувачам високого рівня списку не дуже важливо, як він реально реалізований, і їх слід ізолювати від цих деталей. Уявімо, що Java не відкрила Listінтерфейс, а лише конкретний Listклас, який є насправді тим, що LinkedListзараз є. Усі розробники Java розробили б свій код, щоб він відповідав деталям реалізації: уникайте випадкового доступу, додайте кеш для прискорення доступу або просто повторного втілення ArrayListсамостійно, хоча це було б несумісне з усім іншим кодом, який насправді працює Listлише з ним. Це було б жахливо ... Але тепер уявіть, що майстри Java насправді усвідомлюють, що пов'язаний список жахливий для більшості фактичних випадків використання, і вирішили переключитися на список масивів лише для своїхListклас доступний. Це вплине на ефективність будь-якої програми Java у світі, і люди не будуть раді цього. І головний винуватець у тому, що дані про впровадження були доступні, і розробники припускали, що ці деталі є постійним контрактом, на який вони можуть розраховувати. Ось чому важливо приховати деталі реалізації та визначити лише абстрактний контракт. Це мета інтерфейсу: визначити, який тип введення приймає метод, і який вихід очікується, не оголюючи всіх кишок, які спокушали програмістів налаштувати свій код, щоб відповідати внутрішнім деталям, які можуть змінитися з будь-яким майбутнім оновленням .

Абстрактний клас знаходиться посередині між інтерфейсами та конкретними класами. Він повинен допомогти реалізаціям спільного або нудного коду. Наприклад, AbstractCollectionпередбачено базові реалізації для isEmptyрозміру, що дорівнює 0, containsяк ітерацію та порівняння, addAllяк повторення add, і так далі. Це дозволяє реалізаціям зосередити увагу на важливих частинах, які відрізняються між собою: як насправді зберігати та отримувати дані.

Інша перспектива: API та SPI

Інтерфейси - це шлюзи з низькою когезією між різними частинами коду. Вони дозволяють бібліотекам існувати та розвиватися, не порушуючи кожного користувача бібліотеки, коли щось внутрішньо змінюється. Це називається інтерфейс прикладного програмування , а не класи програми програмування. У меншому масштабі вони також дозволяють багатьом розробникам успішно співпрацювати над масштабними проектами, відокремлюючи різні модулі через добре задокументовані інтерфейси.

Анотаційні класи - це помічники з високою згуртованістю, які використовуватимуться при реалізації інтерфейсу, передбачаючи певний рівень деталізації реалізації. Крім того, абстрактні класи використовуються для визначення SPI, інтерфейсів постачальника послуг.

Різниця між API та SPI є тонкою, але важливою: для API фокус робиться на тому, хто його використовує , а для SPI - фокус на тому, хто його реалізує .

Додавання методів до API просто, усі існуючі користувачі API все одно будуть компілювати. Додавання методів до SPI важко, оскільки кожному постачальнику послуг (конкретна реалізація) доведеться впроваджувати нові методи. Якщо інтерфейси використовуються для визначення SPI, постачальнику доведеться випускати нову версію кожного разу, коли контракт SPI буде змінено. Якщо замість цього використовуються абстрактні класи, нові методи можна або визначити через існуючі абстрактні методи, або як порожні throw not implemented exceptionзаглушки, що дозволить принаймні зіставити та запустити старішу версію реалізації служби.

Примітка про методи Java 8 та методи за замовчуванням

Хоча Java 8 представила методи інтерфейсів за замовчуванням для інтерфейсів, що робить лінію між інтерфейсами та абстрактними класами ще більш розмитою, але це було не таким чином, що реалізація може повторно використовувати код, а щоб полегшити зміну інтерфейсів, які служать і API, і як SPI (або неправильно використовуються для визначення SPI замість абстрактних класів).

"Книга знань"

Технічні деталі, надані у відповіді ОП, вважаються «книжковими знаннями», оскільки це, як правило, підхід, який використовується в школі та в більшості книг з технологій про мову: що таке річ, а не як її використовувати на практиці, особливо у великих масштабах .

Ось аналогія: передбачуване питання було:

Що краще орендувати на випускний вечір, автомобіль або готельний номер?

Технічна відповідь звучить так:

Добре, що в машині ви можете це зробити раніше, але в готельному номері ви можете зробити це зручніше. З іншого боку, готельний номер знаходиться лише в одному місці, тоді як у машині ви можете це зробити в багатьох місцях, наприклад, скажімо, ви можете поїхати до місця виду, щоб побачити прекрасний вигляд, або в театр для проїзду, або в багатьох інших місцях, або навіть у більш ніж одному місці. Також в номері готелю є душ.

Це все правда, але повністю пропускає моменти, що це дві абсолютно різні речі, і обидві можуть бути використані одночасно для різних цілей, а аспект "робити це" не є найважливішим у будь-якому з двох варіантів . У відповіді бракує перспективи, вона показує незрілий спосіб мислення, водночас правильно подаючи справжні "факти".


Ви мали на увазі "низька муфта"?
користувач2418306

@ user2418306 Ні, згуртованість - це більш загальний термін, що включає сполучення, хоча вони є близькими синонімами, і будь-який термін працював би.
Сергіу Думітріу

9

А як думати наступним чином:

  • Зв'язок між класом і абстрактним класом має тип "є-а"
  • Зв'язок між класом та інтерфейсом має тип "has-a"

Отже, коли у вас є абстрактний клас Ссавці, підклас Людина та інтерфейс Водіння, то ви можете сказати

  • кожна людина - ссавець
  • у кожної людини є водіння (поведінка)

Моя пропозиція полягає в тому, що фраза знань про книгу вказує на те, що він хотів почути смислову різницю між обома (як і інші, які вже тут запропоновані).


9

Інтерфейс - це "контракт", де клас, який реалізує контракт, обіцяє реалізувати методи. Приклад, коли мені довелося писати інтерфейс замість класу, коли я оновлював гру з 2D до 3D. Мені довелося створити інтерфейс для обміну класами між 2D та 3D версією гри.

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

Тоді я можу реалізувати методи, що базуються на оточенні, поки ще я можу викликати ці методи з об'єкта, який не знає, яку версію гри завантажує.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Зазвичай в ігровому світі світ може бути абстрактним класом, який виконує методи гри:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

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

6

Абстрактні заняття - це не чиста абстракція. Це колекція конкретних (реалізованих методів), а також непроведених методів. Але інтерфейси є чистою абстракцією. Це лише безпроблемні методи, а не конкретні методи.

Чому абстрактні заняття?

  1. Якщо користувач хоче написати загальну функціональність для всіх об'єктів.
  2. Абстрактні класи - найкращий вибір для повторного втілення в майбутньому, щоб додати більше функціональності, не впливаючи на кінцевого користувача.

Чому інтерфейси?

  1. Якщо користувач хоче написати інший функціонал, це буде інша функціональність на об'єктах.
  2. Інтерфейси - найкращий вибір, який, якщо немає необхідності змінювати вимоги після опублікування інтерфейсу.

5

Інтерфейс , як набір генів, які публічно задокументовані , щоб мати якийсь - то ефект: ДНК тест сказати мені чи є у мене їх - і якщо я роблю, я можу публічно дати зрозуміти, що я «носій "і частина моєї поведінки чи стану відповідатиме їм. (Звичайно, у мене може бути багато інших генів, які надають ознаки поза цією сферою.)

Абстрактний клас подібний до мертвому родоначальнику однієї статі виду (*): Вона не може бути притягнута до життя , але живий (тобто неабстрактне ) нащадках успадковує всі її гени.

(*) Щоб розтягнути цю метафору, скажімо, що всі представники виду живуть до одного віку. Це означає, що всі предки мертвого предка також повинні бути мертвими - і так само всі нащадки живого предка повинні бути живими.


4

Я беру співбесіди на роботі, і я б дуже негативно дивився на вашу відповідь (вибачте, але я дуже чесний). Це звучить так, ніби ви читали про різницю і переглянули відповідь, але, можливо, ви ніколи не використовували її на практиці.

Хороше пояснення того, чому ви використовуєте кожен, може бути набагато кращим, ніж точне пояснення різниці. Роботодавці ультиматлі хочуть, щоб програмісти робили речі, які їх не знають, що може бути важко продемонструвати в інтерв'ю. Відповідь, яку ви дали, буде добре, якщо подавати заявку на технічну або документаційну роботу, але не роль розробників.

Найкраща удача з інтерв'ю в майбутньому.

Також моя відповідь на це питання стосується скоріше техніки інтерв'ю, а не технічного матеріалу, який ви надали. Можливо, подумайте читати про це. https://workplace.stackexchange.com/ може стати прекрасним місцем для подібних речей.


1
Не могли б ви сказати мені, як ви відповіли на це? Можливо, це може допомогти мені.
code_fish

дати вам відповідь пропонує набагато менше, ніж допомогти вам її розробити, в основному наведіть практичний приклад того, коли ви використовували б кожен, і поясніть, чому кожен підходить для різних завдань.
Адріан

4

Ви вибираєте Інтерфейс у Java, щоб уникнути проблеми з алмазами при багатократному успадкуванні .

Якщо ви хочете, щоб всі ваші методи були реалізовані вашим клієнтом, ви перейдете на інтерфейс. Це означає, що ви розробляєте всю програму абстрактно.

Ви вибираєте абстрактний клас, якщо вже знаєте, що спільного. Наприклад, візьміть абстрактний клас Car. На вищому рівні ви реалізуєте такі загальноприйняті методи, як автомобіль calculateRPM(). Це звичайний метод, і ви дозволяєте клієнту реалізовувати його власну поведінку, наприклад,
calculateMaxSpeed()тощо. Ймовірно, ви б це пояснили, наводячи кілька прикладів у реальному часі, з якими ви стикалися у своїй щоденній роботі.



3

Основна відмінність того, що я зауважив, полягала в тому, що абстрактний клас надає нам деяку загальну поведінку, реалізовану вже, а підкласи повинні лише реалізувати відповідну їм функціональність. де інтерфейс визначає лише те, які завдання потрібно виконати, а інтерфейси не будуть реалізовані. Я можу сказати, що він визначає договір між собою та реалізованими класами.


3

Навіть я стикався з тим самим питанням у кількох інтерв'ю, і повірте, це робить ваш час нещасним, щоб переконати інтерв'юера. Якщо мені притаманні всі відповіді зверху, то мені потрібно додати ще один ключовий момент, щоб зробити його більш переконливим і використовувати ОО в найкращих випадках

Якщо ви не плануєте жодних змін у правилах , для підкласу, який слід дотримуватися, на довге майбутнє перейдіть за інтерфейсом, оскільки ви не зможете його змінювати, і якщо ви це зробите, вам потрібно перейти до зміни у всіх інших підкласах, тоді як, якщо ви думаєте, ви хочете повторно використовувати функціонал, встановити деякі правила, а також зробити його відкритим для модифікації , перейдіть до класу Анотація.

Подумайте таким чином, ви використовували послугу споживання або ви надали якийсь код у світі, і у вас є можливість щось змінити, припустимо, перевірка безпеки. Якщо я буду споживачем цього коду та одного ранку після оновлення, я знайди всі прочитані позначки в моєму Eclipse, вся програма закрита. Тому для запобігання таких кошмарів використовуйте «Анотація над інтерфейсами»

Я думаю, це може певною мірою переконати інтерв'юєра ... Щасливі інтерв'ю попереду.


2

Коли я намагаюся поділити поведінку між двома близькоспорідненими класами, я створюю абстрактний клас, який відповідає загальній поведінці і служить батьківським для обох класів.

Коли я намагаюся визначити тип, перелік методів, якими користувач мого об’єкта може надійно закликати, тоді я створюю інтерфейс.

Наприклад, я ніколи не створював би абстрактний клас з 1 конкретним підкласом, оскільки абстрактні класи стосуються спільної поведінки. Але я міг би дуже добре створити інтерфейс лише з однією реалізацією. Користувач мого коду не дізнається, що існує лише одна реалізація. Дійсно, у майбутньому випуску може бути декілька реалізацій, які є підкласами якогось нового абстрактного класу, який навіть не існував під час створення інтерфейсу.

Це могло здатися занадто книжковим (хоча я ніколи не бачив, щоб це було так, ніби я згадую). Якби інтерв'юер (або ОП) справді хотів більше мого особистого досвіду з цього приводу, я був би готовий, щоб анекдоти інтерфейсу склалися з необхідності та візово.

І ще одна річ. Тепер Java 8 дозволяє вставити код за замовчуванням в інтерфейс, додатково розмиваючи рядок між інтерфейсами та абстрактними класами. Але з того, що я бачив, ця особливість надмірно використовується навіть виробниками основних бібліотек Java. Ця функція була додана, і це правильно, щоб можна було розширити інтерфейс, не створюючи бінарної несумісності. Але якщо ви створюєте абсолютно новий тип, визначаючи інтерфейс, тоді інтерфейс повинен бути ПОСЛІДНО інтерфейсом. Якщо ви хочете також надати загальний код, то будь-якими способами складіть клас помічників (абстрактний або конкретний). Не завантажуйте свій інтерфейс з самого початку функціоналом, який ви можете змінити.


2

Основна відмінність інтерфейсу від абстрактного класу полягає в тому, що інтерфейс підтримує множинне успадкування, але не абстрактний клас.

В абстрактному класі також можна надати всі абстрактні методи, такі як інтерфейс.

чому потрібен абстрактний клас?

У деяких сценаріях, обробляючи запит користувача, абстрактний клас не знає, що має намір користувач. У цьому сценарії ми визначимо один абстрактний метод у класі та запитаємо користувача, який розширює цей клас, будь ласка, надайте свій намір у абстрактному методі. У цьому випадку абстрактні заняття дуже корисні

Для чого потрібен інтерфейс?

Скажімо, у мене є робота, в якій я не маю досвіду в цій галузі. Наприклад, якщо ви хочете побудувати будівлю чи дамбу, то що ви будете робити в цьому сценарії?

  1. ви визначите, які ваші вимоги, і укладете договір з цими вимогами.
  2. Потім зателефонуйте до тендерів, щоб створити ваш проект
  3. Хто коли-небудь будував проект, той повинен відповідати вашим вимогам. Але логіка побудови відрізняється від одного постачальника до іншого постачальника.

Тут я не переймаюся логікою того, як вони побудували. Кінцевий об'єкт задовольняв мої вимоги чи ні, це лише мій ключовий момент.

Тут ваші вимоги називаються інтерфейсом, а конструктори називаються реалізатором.


2

Кількома словами я відповів би так:

  • успадкування через ієрархію класів передбачає успадкування держави ;
  • оскільки успадкування через інтерфейси означає успадкування поведінки ;

Абстрактні класи можна трактувати як щось середнє між цими двома випадками (воно вводить певний стан, але також зобов'язує вас визначити поведінку), повністю абстрактний клас - це інтерфейс (це подальший розвиток класів складається з віртуальних методів лише в C ++, оскільки наскільки мені відомо про його синтаксис).

Звичайно, починаючи з Java 8, речі дещо змінилися, але ідея все одно та сама.

Я думаю, що цього достатньо для типового інтерв'ю Java, якщо ви не опитуєтесь до команди-компілятора.


1

З того, що я розумію, інтерфейс, який складається з кінцевих змінних та методів без реалізацій, реалізується класом для отримання групи методів або методів, які пов'язані один з одним. З іншого боку, абстрактний клас, який може містити не остаточні змінні та методи з реалізаціями, зазвичай використовується як керівництво або як суперклас, від якого успадковуються всі споріднені чи подібні класи. Іншими словами, абстрактний клас містить усі методи / змінні, якими поділяються всі його підкласи.


1

В абстрактному класі можна записати реалізацію методів за замовчуванням! Але в інтерфейсі не можна. В основному, в інтерфейсі існують чисті віртуальні методи, які повинні бути реалізовані класом, який реалізує інтерфейс.


1

Так, ваші відповіді були технічно правильними, але там, де ви пішли не так, не показуючи їм, ви розумієте переваги та недоліки вибору одного за іншим. Крім того, вони, ймовірно, стурбовані / лякалися про сумісність своєї кодової бази з оновленнями в майбутньому. Цей тип відповіді, можливо, допоміг (окрім сказаного):

"Вибір абстрактного класу над класом інтерфейсу залежить від того, яким ми будемо проектувати майбутнє коду.

Абстрактні класи дозволяють покращити сумісність вперед, оскільки ви можете продовжувати додавати поведінку до абстрактного класу в майбутнє, не порушуючи існуючий код -> це неможливо з класом інтерфейсу.

З іншого боку, інтерфейсні класи є більш гнучкими, ніж абстрактні класи. Це тому, що вони можуть реалізувати кілька інтерфейсів . Річ у тім, що Java не має декількох успадків, тому використання абстрактних класів не дозволить вам використовувати будь-яку іншу структуру ієрархії класів ...

Отже, зрештою, хорошим загальним правилом є: Віддавайте перевагу використанню класів інтерфейсів, коли у вашій базі коду немає існуючих / типових реалізацій. І використовуйте абстрактні класи, щоб зберегти сумісність, якщо ви знаєте, що в майбутньому ви будете оновлювати свій клас. "

Удачі у вашому наступному інтерв'ю!


1

Я спробую відповісти, використовуючи практичний сценарій, щоб показати різницю між ними.

Інтерфейси оснащені нульовою корисною навантаженням, тобто жоден стан не повинен підтримуватися, і, отже, кращий вибір просто асоціювати контракт (можливість) з класом.

Наприклад, скажіть, у мене є клас Task, який виконує якусь дію, тепер для виконання завдання в окремому потоці мені дійсно не потрібно розширювати клас Thread, а кращим вибором є зробити завдання реалізувати інтерфейс Runnable (тобто реалізувати його метод run () ), а потім передайте об’єкт цього класу завдань екземпляру Thread і викликайте його метод start ().

Тепер ви можете запитати, що якщо Runnable був абстрактним класом?

Ну технічно це було можливо, але дизайн розумний, що було б причиною поганого вибору:

  • Runnable не має з цим пов’язаного стану, і він також не пропонує будь-якої реалізації за замовчуванням для методу run ()
  • Завдання доведеться розширити, таким чином він не міг поширити жоден інший клас
  • Завдання не може запропонувати як спеціалізацію до класу Runnable, все що потрібно - це перекрити метод run ()

Іншими словами, клас Task потребував можливості запуску в потоці, якого він досяг, реалізуючи інтерфейси Runnable, що розширюють клас Thread, що зробить його потоком.

Просто поставте нам інтерфейс для визначення можливості (контракту), використовуючи при цьому абстрактний клас для визначення скелету (загального / часткового) його реалізації.

Відмова: дурний приклад випливає, намагайтеся не судити :-P

interface Forgiver {
    void forgive();
}

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

Тепер вам було надано вибір бути GodLike, але ви можете вибрати лише Forgiver (тобто не GodLike) і зробити:

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

Або ви можете вибрати GodLike і зробити:

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

PS з інтерфейсом java 8 також може мати статичні методи, а також за замовчуванням (реалізація реалізованої реалізації), і, таким чином, різниця між інтерфейсом в / ч та абстрактним класом ще більше звужується.


1

Майже все тут вже висвітлено. Додавання ще одного пункту щодо практичної реалізації abstractкласу:

abstractКлючове слово також використовується лише для запобігання екземпляру класу. Якщо у вас конкретний клас, який ви не хочете створювати, - зробіть це abstract.


1

Гм, зараз люди голодні практичного підходу, ви абсолютно праві, але більшість інтерв'юєрів виглядає відповідно до їхніх вимог і хочуть практичного підходу.

закінчивши свою відповідь, слід перейти на приклад:

Анотація:

наприклад, у нас функція зарплати, яка має певний параметр, спільний для всіх працівників. тоді ми можемо мати абстрактний клас під назвою CTC з частково визначеним тілом методу, і він буде розширений всіма типами співробітників і буде перероблений відповідно до їх додаткових вигод. Для загальної функціональності.

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

Інтерфейс

Інтерфейс в java дозволяє мати функціональні можливості interfcae, не розширюючи цей, і вам потрібно бути зрозумілим з реалізацією підпису функціональності, який ви хочете внести у свою програму. це змусить вас мати дефінітон. Для різної функціональності.

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

}

Ви можете мати таку вимушену діяльність з абстрактним класом теж за допомогою визначених методів як абстрактних, тепер клас, який розширює абстрактний ремінь класу абстрактний, поки він не перекриє цю абстрактну функцію.


1

З того, що я розумію і як підходжу,

Інтерфейс - це як специфікація / контракт; будь-який клас, який реалізує клас інтерфейсу, повинен реалізувати всі методи, визначені в абстрактному класі (крім методів за замовчуванням (введених у Java 8))

Тоді як я визначаю конспект класу, коли знаю, що реалізація потрібна для деяких методів класу та деяких методів, я все ще не знаю, що буде реалізацією (ми можемо знати функцію підпису, але не реалізацію). Я роблю це для того, щоб пізніше, у частині розробки, коли я знаю, як ці методи реалізувати, я можу просто розширити цей абстрактний клас та реалізувати ці методи.

Примітка. У методах інтерфейсу ви не можете мати тіло функції, якщо метод не є статичним або за замовчуванням.


0

Я вважаю, що інтерв'юер намагався досягти, ймовірно, була різниця між інтерфейсом та реалізацією.

Інтерфейс - не Java-інтерфейс, а "інтерфейс" у більш загальних рисах - до кодового модуля - це, в основному, договір, укладений з кодом клієнта, який використовує інтерфейс.

Реалізація кодового модуля - це внутрішній код, який змушує модуль працювати. Часто ви можете реалізувати певний інтерфейс більш ніж одним різним способом і навіть змінити імплементацію, без того, щоб клієнтський код навіть не знав про зміни.

Інтерфейс Java слід використовувати лише як інтерфейс у вищезазначеному загальному сенсі, щоб визначити, як клас поводиться на користь клієнтського коду за допомогою класу, не вказуючи жодної реалізації. Таким чином, інтерфейс включає підписи методів - імена, типи повернення та списки аргументів - для методів, які, як очікується, будуть викликані клієнтським кодом, і в принципі має бути достатньо Javadoc для кожного методу, що описує, що цей метод робить. Найбільш переконливою причиною використання інтерфейсу є те, якщо ви плануєте мати декілька різних реалізацій інтерфейсу, можливо, вибираючи програму залежно від конфігурації розгортання.

Абстрактний клас Java, навпаки, забезпечує часткову реалізацію класу, а не основну мету вказувати інтерфейс. Він повинен використовуватися, коли кілька класів діляться кодом, але коли очікується, що підкласи також будуть частиною реалізації. Це дозволяє спільному коду з'являтися лише в одному місці - абстрактному класі - при цьому ясно, що частини реалізації відсутні в абстрактному класі і, як очікується, будуть надані підкласами.


0

Ваша відповідь правильна, але інтерв'юер потребує, щоб Ви розмежовувались відповідно до інженерної програми, а не відповідно до деталей Java.

Прості слова:

Інтерфейс схожий на інтерфейс магазину, все, що на ньому зображено, має бути там, у магазині, тому будь-який метод в Інтерфейсі повинен бути реалізований у конкретному класі. А що робити, якщо деякі класи поділяють деякі точні методи, а в інших - різні. Припустимо, інтерфейс - це магазин, який містить дві речі, і припустимо, у нас два магазини містять спортивний інвентар, але в одному є додатковий одяг, а в іншому - додаткове взуття. Отже, ви робите абстрактний клас для спорту, який реалізує метод "Спорт", а інший метод залишає без змін. Тут абстрактний клас означає, що цей магазин не існує сам, але він є базою для інших класів / магазинів. Таким чином ви впорядковуєте код, уникаючи помилок реплікації коду, об'єднуючи код і забезпечуючи повторну корисність деяким іншим класом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.