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

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

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

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

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

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

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

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

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

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

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

Где я неправ?

35 ответов

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

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

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

Я старался изо всех сил, и надеюсь, это очистит ваши сомнения.

Ничто не идеально в этом мире. Возможно, они ожидали большего от практического подхода.

Но после вашего объяснения вы можете добавить эти строки с немного другим подходом.

  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(), иначе компилятор выдаст ошибку времени компиляции.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Резюме

  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 вместо абстрактных классов).

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

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

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

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

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

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

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

Интерфейс - это "контракт", в котором класс, реализующий контракт, обещает реализовать методы. Примером, когда я должен был написать интерфейс вместо класса, был, когда я обновлял игру от 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;
    }

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

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

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

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

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

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

Почему абстрактные классы?

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

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

  1. Если пользователь хочет написать другую функциональность, это будет другой функциональностью объектов.
  2. Интерфейсы являются лучшим выбором, если нет необходимости изменять требования после публикации интерфейса.

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

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

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

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

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

Абстрактный класс подобен мертвому предку однополого вида(*): она не может быть воплощена в жизнь, но живой (то есть неабстрактный) потомок наследует все ее гены.

(*) Чтобы растянуть эту метафору, скажем, все представители вида живут до одного возраста. Это означает, что все предки мертвого предка также должны быть мертвы - и аналогично, все потомки живого предка должны быть живы.

В двух словах я бы ответил так:

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

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

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

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

Вы выбираете Интерфейс в Java, чтобы избежать Алмазной Проблемы в множественном наследовании.

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

Вы выбираете абстрактный класс, если вы уже знаете, что общего. Например возьмите абстрактный класс Car, На более высоком уровне вы реализуете общие методы автомобиля, такие как calculateRPM(), Это распространенный метод, и вы позволяете клиенту реализовать свое собственное поведение, как
calculateMaxSpeed() и т. д. Возможно, вы бы объяснили, приведя несколько примеров в реальном времени, с которыми вы сталкивались в своей повседневной работе.

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

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

Желаем удачи с интервью в будущем.

Также мой ответ на этот вопрос больше о технике интервью, а не о технических материалах, которые вы предоставили. Возможно, стоит почитать об этом. https://workplace.stackexchange.com/ может быть отличным местом для такого рода вещей.

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

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

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

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

Интерфейс чисто абстрактный. у нас нет никакого кода реализации в интерфейсе.

Абстрактный класс содержит как методы, так и его реализацию.

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

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

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

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

Если хотите, то скажите, что абстрактный класс часто реализует часть интерфейса - работа ваша!

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

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

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

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

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

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

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

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

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

Зачем нужен интерфейс?

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

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

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

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

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

после окончания ответа вам следует перейти к примеру:

Аннотация:

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

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

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

}

class PermanentOne implements EmployeType
{

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

}

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

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

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

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

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

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

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

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

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

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

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

Ваш ответ в порядке, но я думаю, что он искал такой ответ:

Абстрактный класс

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

Интерфейс

  • Интерфейс может иметь стандартные, статические и абстрактные методы.
  • Интерфейс поддерживает множественное наследование.
  • Интерфейс имеет только статические и конечные переменные.
  • Интерфейс не может обеспечить реализацию абстрактного класса.

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

Вот объяснение, посвященное Java 8, которое пытается показать ключевые различия между абстрактными классами и интерфейсами и охватывает все детали, необходимые для экзамена Java Associate Exam.

Ключевые понятия:

  • Класс может extend только один класс, но он может implement любое количество интерфейсов
  • Интерфейсы определяют, что делает класс, абстрактные классы определяют, что это такое
  • Абстрактные классы - это классы. Их нельзя создать, но в остальном они ведут себя как обычные классы.
  • Оба могут иметь абстрактные методы и статические методы.
  • Интерфейсы могут иметь методы по умолчанию и статические конечные константы, а также могут расширять другие интерфейсы.
  • Все члены интерфейса общедоступны (до Java 9)

Интерфейсы определяют, что делает класс, абстрактные классы определяют, что это такое

Пер Роуди Грин:

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

До Java 8 ответ @Daniel Lerps был точным, что интерфейсы похожи на контракт, который должен выполнять класс реализации.

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

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

Абстрактные классы - это классы

Вот некоторые из обычных функций классов, которые доступны в абстрактных классах, но не в интерфейсах:

  • Переменные экземпляра / не конечные переменные. И поэтому…
  • Методы, которые могут получить доступ и изменить состояние объекта
  • Частные / защищенные члены (но см. Примечание по Java 9)
  • Возможность расширения абстрактных или конкретных классов
  • Конструкторы

Обратите внимание на абстрактные классы:

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

Абстрактные методы

И абстрактные классы, и интерфейсы могут иметь от нуля до многих абстрактных методов. Абстрактные методы:

  • Сигнатуры методов без тела (т.е. нет {})
  • Должен быть отмечен abstractключевое слово в абстрактных классах. В интерфейсах это ключевое слово не нужно
  • Не может быть private (потому что они должны быть реализованы другим классом)
  • Не может быть final (потому что у них еще нет тел)
  • Не может быть static(по причинам)

Также обратите внимание, что:

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

Статические методы

Статический метод абстрактного класса можно вызвать напрямую с помощью MyAbstractClass.method(); (т.е. точно так же, как для обычного класса, и его также можно вызвать через класс, расширяющий абстрактный класс).

Интерфейсы также могут иметь статические методы. Их можно вызвать только через имя интерфейса (MyInterface.method();). Эти методы:

  • Не может быть abstract, то есть должен иметь тело (см. выше "по причинам")
  • Не default (увидеть ниже)

Методы по умолчанию

Интерфейсы могут иметь методы по умолчанию, которые должны иметь defaultключевое слово и тело метода. Они могут ссылаться только на другие методы интерфейса (и не могут ссылаться на конкретное состояние реализации). Эти методы:

  • Не static
  • Не abstract (у них есть тело)
  • Не может быть final (название "по умолчанию" указывает на то, что они могут быть отменены)

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

Интерфейсы могут иметь статические конечные константы

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

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

Все участники интерфейса общедоступны

В Java 8 предполагается, что все элементы интерфейсов (и сами интерфейсы) public, и не может быть protected или private(но Java 9 допускает частные методы в интерфейсах).

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

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

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

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

Другие вопросы по тегам