Как мне объяснить разницу между интерфейсом и абстрактным классом?

469

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

Вот мой ответ:

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

Переменные, объявленные в интерфейсе Java, по умолчанию являются окончательными. Абстрактный класс может содержать неконечные переменные.

Члены интерфейса Java являются общедоступными по умолчанию. Абстрактный класс Java может иметь обычные разновидности членов класса, такие как private, protected и т. Д.

Интерфейс Java должен быть реализован с использованием ключевого слова «Implements»; Абстрактный класс Java должен быть расширен с помощью ключевого слова «extends».

Интерфейс может расширять только другой интерфейс Java, абстрактный класс может расширять другой класс Java и реализовывать несколько интерфейсов Java.

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

Однако интервьюер не был удовлетворен и сказал мне, что это описание представляет собой « книжное знание ».

Он попросил у меня более практического ответа, объяснив, когда я выберу абстрактный класс вместо интерфейса, используя практические примеры .

Где я неправ?

мыслитель
источник
32
Может быть, ваш ответ выглядел так, будто вы говорите что-то, чего не понимаете? Может случиться так, что вам просто нужно изменить стиль сообщения на тот, который больше похож на ваши собственные слова.
Кирилл Кобелев
19
Вы ответили списком (вполне корректных) технических отличий. Интервьюер, скорее всего, искал более концептуальный ответ (например, на каком основании можно было бы выбрать между использованием интерфейса и абстрактного класса).
Тед Хопп
15
Вы забыли сказать, что у абстрактных классов есть конструкторы, хотя вы не можете создать экземпляр абстрактного класса const. используется дочерними классами. Интерфейсы указывают «что», но не «как», потому что они определяют контракт (список методов), пока возбуждаются. Класс также может указывать «как» (реализовать мет.). Используя int. Вы можете эмулировать множественное наследование (класс может реализовывать несколько int., но расширять только один класс). Используя int. Вы можете иметь базовый тип для DIF. Семейства: Flyer f = новый самолет (); Flyer f2 = новый Bird (); Птица и Самолет не соответствуют одному семейству, но оба могут летать (летчики).
Франсиско Гольдштейн
7
Что касается интерфейсов java8, то они могут содержать методы, поэтому помимо концепции ОО эти так называемые «различия» могут измениться в любой день.
носитель кольца
15
У меня нет проблем с вашим ответом, и я не думаю, что у интервьюера есть какое-либо дело, чтобы насмехаться над «знанием книг». Интервьюеры не всегда знают правильные ответы на вопросы, которые они задают, а некоторые интервью только предупреждают вас, чтобы вы не работали там.
Маркиз Лорн

Ответы:

513

Сначала приведу пример:

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

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

Вимал Бера
источник
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 не позволяет расширять несколько классов, потому что это приводит к «проблеме алмаза», когда компилятор не может решить, какой метод суперкласса использовать. При использовании методов по умолчанию проблема алмазов будет возникать и для интерфейсов. Потому что, если класс реализует оба

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

Интерфейс состоит из одноэлементных переменных (public static final) и открытых абстрактных методов. Обычно мы предпочитаем использовать интерфейс в режиме реального времени, когда мы знаем, что делать, но не знаем, как это сделать .

Эту концепцию можно лучше понять на примере:

Рассмотрим класс оплаты. Оплата может быть произведена разными способами, такими как PayPal, кредитная карта и т. Д. Поэтому мы обычно принимаем Платеж как наш интерфейс, который содержит 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.
    }
}

Если мы добавим методы (конкретные / абстрактные) в будущем к данному абстрактному классу, тогда классу реализации не потребуется изменять свой код. Однако, если мы добавим методы в интерфейс в будущем, мы должны добавить реализации ко всем классам, которые реализовали этот интерфейс, иначе произойдут ошибки времени компиляции.

Существуют и другие отличия, но они могут быть такими, как ожидал ваш интервьюер. Надеюсь, это было полезно.

Satya
источник
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-класс может реализовывать несколько интерфейсов, и каждый интерфейс может определять метод по умолчанию с одинаковой сигнатурой метода, следовательно, унаследованные методы могут конфликтовать друг с другом.

Рассмотрим ниже пример,

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 по умолчанию помогут нам избежать использования вспомогательных классов, например, все методы класса Collections могут быть предоставлены в самих интерфейсах.
  4. Методы интерфейса Java по умолчанию помогут нам в удалении базовых классов реализации, мы можем предоставить реализацию по умолчанию, и классы реализации могут выбрать, какой из них переопределить.
  5. Одной из основных причин введения методов по умолчанию в интерфейсах является усовершенствование API коллекций в Java 8 для поддержки лямбда-выражений.
  6. Если какой-либо класс в иерархии имеет метод с такой же сигнатурой, то методы по умолчанию становятся неактуальными. Метод по умолчанию не может переопределить метод из java.lang.Object. Рассуждения очень просты, потому что Object является базовым классом для всех классов Java. Таким образом, даже если у нас есть методы класса Object, определенные как методы по умолчанию в интерфейсах, это будет бесполезно, потому что метод класса Object всегда будет использоваться. Вот почему во избежание путаницы у нас не может быть методов по умолчанию, которые переопределяют методы класса Object.
  7. Методы интерфейса Java по умолчанию также называются методами защитника или методами виртуального расширения.

Ссылка на ресурс:

  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 Print ::

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, чтобы удалить служебные классы, такие как Коллекции, и переместить все его статические методы в соответствующий интерфейс, который было бы легко найти и использовать.

Функциональные интерфейсы 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. Совместное использование общего состояния среди связанных классов (состояние может быть изменено в конкретных классах)

Похожие сообщения:

Интерфейс против абстрактного класса (общий ОО)

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

Просматривая эти примеры, вы можете понять, что

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

Равиндра Бабу
источник
Что вы имеете в виду, говоря "контракт без гражданства"? Это пункт 1 об интерфейсах
Максим Дмитриев
1
Отсутствие изменчивого состояния. Поскольку интерфейс может иметь константы, данные могут быть видоизменены в отличие от абстрактных классов
Равиндра Бабу
1
Исправление в вышеприведенном утверждении. В интерфейсе данные не могут быть видоизменены в отличие от абстрактного класса
Равиндра Бабу
2
это лучший ответ. Он не только обращается к Java8, но также объясняет, в каких конкретных ситуациях вы будете использовать любую из них.
Shuklaswag
Понятие statelessв интерфейсе - хороший хит. Интерфейс не может иметь никакого состояния (Интерфейс может иметь константы, но они являются окончательными / статическими, поэтому неизменяемыми).
Кайхуа
22

Ваше объяснение выглядит прилично, но, может быть, выглядело так, будто вы все это читали из учебника? : - /

Что меня больше беспокоит, так это насколько твердым был ваш пример? Вы удосужились включить почти все различия между абстрактными и интерфейсами?

Лично я бы предложил эту ссылку: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

для исчерпывающего списка различий ..

Надеюсь, что это поможет вам и всем другим читателям в их будущих интервью

VictorCreator
источник
1
ссылка делится действительно
круто
Вы можете обеспечить реализацию по умолчанию в интерфейсах Java, используя ключевое слово по умолчанию
Ogen
21

Многие младшие разработчики ошибочно считают интерфейсы, абстрактные и конкретные классы незначительными вариациями одного и того же и выбирают один из них исключительно по техническим причинам: нужно ли множественное наследование? Нужно ли какое-то место, чтобы поставить общие методы? Нужно ли беспокоиться о чем-то другом, кроме как о конкретном занятии? Это неправильно, и в этих вопросах скрыта главная проблема: «Я» . Когда вы пишете код для себя, вы редко думаете о других настоящих или будущих разработчиках, работающих над вашим кодом или над ним.

Интерфейсы и абстрактные классы, хотя и кажутся с технической точки зрения схожими, имеют совершенно разные значения и цели.

Резюме

  1. Интерфейс определяет контракт, который некоторая реализация выполнит для вас .

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

Эти два пункта выше - то, что я ищу во время интервью, и это достаточно компактное резюме. Читайте дальше для более подробной информации.

Альтернативное резюме

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

Примером

Иными словами: конкретный класс выполняет реальную работу очень специфическим образом. Например, оператор ArrayListиспользует непрерывную область памяти для компактного хранения списка объектов, который предлагает быстрый произвольный доступ, итерации и изменения на месте, но ужасен при вставках, удалениях и иногда даже добавлениях; между темLinkedListиспользует двойные узлы для хранения списка объектов, который вместо этого предлагает быструю итерацию, изменения на месте и вставку / удаление / добавление, но ужасен при произвольном доступе. Эти два типа списков оптимизированы для разных вариантов использования, и очень важно, как вы собираетесь их использовать. Когда вы пытаетесь выжать производительность из списка, с которым интенсивно взаимодействуете, и когда выбор типа списка зависит от вас, вы должны тщательно выбрать, какой экземпляр вы создаете.

С другой стороны, пользователям высокого уровня списка на самом деле все равно, как он на самом деле реализован, и они должны быть изолированы от этих деталей. Давайте представим, что 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 вместо абстрактных классов).

"Книга знаний"

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

Вот аналогия: предполагается, что вопрос был:

Что лучше арендовать на выпускной вечер, машину или номер в отеле?

Технический ответ звучит так:

Ну, в машине вы можете сделать это раньше, но в гостиничном номере вы можете сделать это более комфортно. С другой стороны, гостиничный номер находится только в одном месте, в то время как в машине вы можете сделать это в большем количестве мест, например, скажем, вы можете поехать на смотровую площадку для прекрасного вида, или в кинотеатр, где можно заехать, или во многих других местах, или даже в более чем одном месте. Также в гостиничном номере есть душ.

Это все верно, но полностью упускает из виду то, что это две совершенно разные вещи, и обе могут использоваться одновременно для разных целей, и аспект «делать это» - не самая важная вещь в любом из двух вариантов , Ответу не хватает перспективы, он показывает незрелое мышление и правильно представляет истинные «факты».

Серджиу Думитриу
источник
Вы имели в виду "низкий уровень связи"?
user2418306
@ user2418306 Нет, сплоченность - это более общий термин, который включает в себя связь, хотя они являются близкими синонимами, и любой из этих терминов сработал бы.
Думитриу
9

Как насчет мышления следующим образом:

  • Отношения между классом и абстрактным классом имеют тип "is-a"
  • Отношения между классом и интерфейсом имеют тип "has-a"

Поэтому, когда у вас есть абстрактный класс Mammals, подкласс Human и интерфейс Driving, тогда вы можете сказать,

  • каждый человек-млекопитающее
  • У каждого Человека есть Вождение (поведение)

Мое предположение состоит в том, что фраза «знание книги» указывает на то, что он хотел услышать семантическое различие между обоими (как другие уже предложили)

akohout
источник
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()и т. Д. Возможно, вы бы объяснили, приведя несколько примеров в реальном времени, с которыми вы сталкивались в своей повседневной работе.

MaheshVarma
источник
3

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


источник
3

Даже я сталкивался с одним и тем же вопросом в нескольких интервью и, поверьте мне, это делает ваше время несчастным, чтобы убедить интервьюера. Если мне присущи все ответы сверху, мне нужно добавить еще один ключевой момент, чтобы сделать его более убедительным и использовать ОО в лучшем виде

Если вы не планируете каких-либо изменений в правилах , подкласс должен соблюдаться в течение длительного времени, перейдите на интерфейс, так как вы не сможете изменить его, и если вы это сделаете, вам нужно перейти на изменения во всех других подклассах, тогда как, если вы думаете, вы хотите повторно использовать функциональность, установить некоторые правила, а также сделать ее открытой для модификации , перейдите к классу Abstract.

Подумайте так, вы использовали услугу расходных материалов или предоставили какой-то код миру, и у вас есть возможность что-то изменить, предположить проверку безопасности. И если я пользуюсь кодом и однажды утром после обновления я найти все метки чтения в моем Eclipse, все приложение не работает. Поэтому, чтобы предотвратить такие кошмары, используйте Abstract over Interfaces

Я думаю, что это может убедить интервьюера до такой степени ... Впереди счастливые интервью.

Винод Базари
источник
2

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

Когда я пытаюсь определить тип, список методов, которые пользователь моего объекта может надежно вызывать, я создаю интерфейс.

Например, я бы никогда не создал абстрактный класс с 1 конкретным подклассом, потому что абстрактные классы связаны с общим поведением. Но я вполне мог бы создать интерфейс только с одной реализацией. Пользователь моего кода не будет знать, что существует только одна реализация. Действительно, в будущем выпуске может быть несколько реализаций, которые все являются подклассами какого-то нового абстрактного класса, которого даже не было, когда я создавал интерфейс.

Это могло бы показаться слишком книжным (хотя я никогда не видел, чтобы это было так, как я помню). Если бы интервьюер (или ОП) действительно хотел больше моего личного опыта по этому вопросу, я был бы готов с анекдотами интерфейса, возникшего по необходимости и наоборот.

Еще кое-что. Java 8 теперь позволяет помещать код по умолчанию в интерфейс, еще больше размывая грань между интерфейсами и абстрактными классами. Но из того, что я видел, эта функция слишком часто используется создателями базовых библиотек Java. Эта функция была добавлена, и это правильно, чтобы сделать возможным расширение интерфейса без создания двоичной несовместимости. Но если вы создаете совершенно новый тип, определяя интерфейс, то интерфейс должен быть просто интерфейсом. Если вы также хотите предоставить общий код, то обязательно создайте вспомогательный класс (абстрактный или конкретный). Не загромождайте свой интерфейс с самого начала функциональностью, которую вы, возможно, захотите изменить.

Teto
источник
2

Основное различие между интерфейсом и абстрактным классом состоит в том, что интерфейс поддерживает множественное наследование, но абстрактный класс - нет.

В абстрактном классе также вы можете предоставить все абстрактные методы, такие как интерфейс.

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

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

Почему требуется интерфейс?

Допустим, у меня есть работа, которой у меня нет опыта в этой области. Например, если вы хотите построить здание или плотину, что вы будете делать в этом сценарии?

  1. Вы определите свои требования и заключите договор с этими требованиями.
  2. Затем позвоните в тендеры, чтобы построить свой проект
  3. Кто когда-либо строит проект, тот должен удовлетворить ваши требования. Но логика построения отличается от одного поставщика к другому поставщику.

Здесь я не беспокоюсь о логике, как они построены. Конечный объект удовлетворял моим требованиям или нет, что только мой ключевой момент.

Здесь ваши требования называются интерфейсом, а конструкторы называются разработчиком.

Дхариси Суреш
источник
2

В нескольких словах я бы ответил так:

  • наследование через иерархию классов подразумевает наследование состояния ;
  • тогда как наследование через интерфейсы означает наследование поведения ;

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

Конечно, начиная с Java 8 все немного изменилось, но идея остается прежней.

Думаю, этого вполне достаточно для типичного интервью на Java, если вы не проходите собеседование с командой компиляторов.

Глеб Стромов
источник
1

Из того, что я понимаю, Интерфейс, который состоит из конечных переменных и методов без реализаций, реализуется классом для получения группы методов или методов, которые связаны друг с другом. С другой стороны, абстрактный класс, который может содержать неконечные переменные и методы с реализациями, обычно используется как руководство или как суперкласс, от которого наследуются все связанные или похожие классы. Другими словами, абстрактный класс содержит все методы / переменные, которые являются общими для всех его подклассов.

марза
источник
1

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

dg_no_9
источник
1

Да, ваши ответы были технически правильными, но если вы ошиблись, это не показывало, что вы понимаете достоинства и недостатки выбора одного из них. Кроме того, они, вероятно, были обеспокоены / взволнованы совместимостью их кодовой базы с обновлениями в будущем. Этот тип ответа мог помочь (в дополнение к тому, что вы сказали):

«Выбор абстрактного класса по сравнению с интерфейсным классом зависит от того, каким мы будем прогнозировать будущее кода.

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

С другой стороны, интерфейсные классы более гибкие, чем абстрактные классы. Это потому, что они могут реализовать несколько интерфейсов . Дело в том, что у Java нет множественного наследования, поэтому использование абстрактных классов не позволит вам использовать любую другую структуру иерархии классов ...

Итак, в конце концов, хорошее общее правило: предпочитайте использовать интерфейсные классы, когда в вашей кодовой базе нет существующих реализаций / реализаций по умолчанию. И используйте Абстрактные классы для сохранения совместимости, если вы знаете, что будете обновлять свой класс в будущем. "

Удачи на следующем собеседовании!

Jaxian
источник
1

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

Интерфейсы поставляются с нулевой полезной нагрузкой, т. Е. Не нужно поддерживать состояние, и, таким образом, это лучший выбор, чтобы просто связать контракт (возможность) с классом.

Например, скажем, у меня есть класс Task, который выполняет какое-то действие, теперь для выполнения задачи в отдельном потоке мне не нужно расширять класс Thread, а лучшим выбором будет сделать так, чтобы Task реализовал интерфейс Runnable (т.е. реализовал его метод run () ), а затем передать объект этого класса Task экземпляру 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 также может иметь статические методы по умолчанию (переопределяемая реализация) и, таким образом, разница между ч / б интерфейсом и абстрактным классом еще более сужена.

sactiw
источник
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";
    }

}

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

RTA
источник
1

Из того, что я понимаю и как я подхожу,

Интерфейс подобен спецификации / контракту, любой класс, реализующий класс интерфейса, должен реализовывать все методы, определенные в абстрактном классе (кроме методов по умолчанию (введено в Java 8))

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

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

Акаш Лодха
источник
0

Я полагаю, что интервьюер пытался понять разницу между интерфейсом и реализацией.

Интерфейс - не интерфейс Java, а «интерфейс» в более общих терминах - для модуля кода - это, по сути, контракт, заключенный с клиентским кодом, использующим интерфейс.

Реализация модуля кода - это внутренний код, который обеспечивает работу модуля. Часто вы можете реализовать конкретный интерфейс несколькими различными способами и даже изменить реализацию без кода клиента, даже не зная об этом изменении.

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

Абстрактный класс Java, напротив, обеспечивает частичную реализацию класса, а не имеет первостепенную цель определения интерфейса. Его следует использовать, когда несколько классов совместно используют код, но когда ожидается, что подклассы также обеспечат часть реализации. Это позволяет общему коду появляться только в одном месте - абстрактном классе - при этом становится ясно, что части реализации отсутствуют в абстрактном классе и, как ожидается, будут предоставлены подклассами.

Уоррен Дью
источник
0

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

Простые слова:

Интерфейс подобен интерфейсу магазина, все, что показано на нем, должно быть в магазине, поэтому любой метод в Интерфейсе должен быть реализован в конкретном классе. А что если некоторые классы используют одни и те же методы, а другие - нет? Предположим, что интерфейс - это магазин, в котором есть две вещи, и предположим, что у нас есть два магазина, в каждом из которых есть спортивное снаряжение, но в одном есть дополнительная одежда, а в другом - обувь. Итак, вы делаете абстрактный класс для Sport, который реализует метод Sports, а другой метод остается нереализованным. Абстрактный класс здесь означает, что этот магазин не существует сам по себе, но он является базой для других классов / магазинов. Таким образом вы организуете код, избегая ошибок репликации кода, унифицируя код и обеспечивая возможность повторного использования другим классом.

Мосаб Шахин
источник