В чем разница между интерфейсом и абстрактным классом?

В чем именно разница между интерфейсом и абстрактным классом?

40 ответов

Решение

Интерфейсы

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

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

Например (псевдокод):

// I say all motor vehicles should look like this:
interface MotorVehicle
{
    void run();

    int getFuel();
}

// My team mate complies and writes vehicle looking that way
class Car implements MotorVehicle
{

    int fuel;

    void run()
    {
        print("Wrroooooooom");
    }


    int getFuel()
    {
        return this.fuel;
    }
}

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


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

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

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

Например:

// I say all motor vehicles should look like this:
abstract class MotorVehicle
{

    int fuel;

    // They ALL have fuel, so lets implement this for everybody.
    int getFuel()
    {
         return this.fuel;
    }

    // That can be very different, force them to provide their
    // own implementation.
    abstract void run();
}

// My teammate complies and writes vehicle looking that way
class Car extends MotorVehicle
{
    void run()
    {
        print("Wrroooooooom");
    }
}

Реализация

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

В Java это правило строго соблюдается, в то время как в PHP интерфейсы являются абстрактными классами без объявленного метода.

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

Как обычно в программировании, есть теория, практика и практика на другом языке:-)

Основные технические различия между абстрактным классом и интерфейсом:

  • Абстрактные классы могут иметь константы, члены, заглушки методов (методы без тела) и определенные методы, тогда как интерфейсы могут иметь только константы и заглушки методов.

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

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

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

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

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

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

Взято из:

http://www.dotnetbull.com/2011/11/difference-between-abstract-class-and.html

http://www.dotnetbull.com/2011/11/what-is-abstract-class-in-c-net.html http://www.dotnetbull.com/2011/11/what-is-interface-in-c-net.html

Объяснение можно найти здесь: http://www.developer.com/lang/php/article.php/3604111/PHP-5-OOP-Interfaces-Abstract-Classes-and-the-Adapter-Pattern.htm

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

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

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

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

Проще говоря, я хотел бы сказать:

интерфейс: для реализации контракта несколькими несвязанными объектами

абстрактный класс: для реализации одинакового или разного поведения среди нескольких связанных объектов

Из документации Oracle

Рассмотрите возможность использования абстрактных классов, если:

  1. Вы хотите поделиться кодом между несколькими тесно связанными классами.
  2. Вы ожидаете, что классы, которые расширяют ваш абстрактный класс, имеют много общих методов или полей или требуют модификаторов доступа, отличных от public (например, protected и private).
  3. Вы хотите объявить нестатические или не финальные поля.

Рассмотрите возможность использования интерфейсов, если:

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

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

Если вы ищете Java как язык программирования, вот еще несколько обновлений:

Java 8 сократила разрыв между interface а также abstract классы в некоторой степени, предоставляя default особенность метода. Интерфейс не имеет реализации для метода, более не действителен в настоящее время.

Обратитесь к этой странице документации для получения более подробной информации.

Посмотрите на этот вопрос SE для примеров кода, чтобы лучше понять.

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

Суть в том, что:

  • Аннотация является объектно-ориентированным. Он предлагает основные данные, которые должен иметь "объект", и / или функции, которые он должен выполнять. Он касается основных характеристик объекта: что у него есть и что он может сделать. Следовательно, объекты, которые наследуются от одного и того же абстрактного класса, имеют общие характеристики (обобщение).
  • Интерфейс ориентирован на функциональность. Он определяет функциональные возможности, которые должен иметь объект. Независимо от того, что это за объект, пока он может выполнять эти функции, которые определены в интерфейсе, это нормально. Это игнорирует все остальное. Объект / класс может содержать несколько (групп) функциональных возможностей; следовательно, класс может реализовать несколько интерфейсов.

Некоторые важные отличия:

В форме таблицы:

разница

Как заявил Джо из javapapers:

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

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

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

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

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

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

7. Интерфейс абсолютно абстрактный и не может быть создан; Абстрактный класс Java также не может быть создан, но может быть вызван, если существует main().

8. По сравнению с абстрактными Java-классами, Java-интерфейсы медленны, так как требуют дополнительной косвенности.

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

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

Я строю здание из 300 этажей

Интерфейс проекта здания

  • Например, Сервлет (I)

Здание построено до 200 этажей - частично завершено --- аннотация

  • Частичная реализация, например, универсальный и HTTP-сервлет

Строительство здания завершено - бетон

  • Полная реализация, например, собственного сервлета

Интерфейс

  • Мы ничего не знаем о реализации, только требования. Мы можем пойти на интерфейс.
  • Каждый метод является публичным и абстрактным по умолчанию
  • Это 100% чистый абстрактный класс
  • Если мы объявляем публичным, мы не можем объявить частным и защищенным
  • Если мы объявляем абстрактный, мы не можем объявить окончательный, статический, синхронизированный, строгий и нативный
  • У каждого интерфейса есть public, static и final
  • Сериализация и переходные процессы не применимы, потому что мы не можем создать экземпляр для в интерфейсе
  • Энергонезависимый, потому что он окончательный
  • Каждая переменная является статической
  • Когда мы объявляем переменную внутри интерфейса, нам нужно инициализировать переменные при объявлении
  • Экземпляр и статический блок не допускаются

Аннотация

  • Частичная реализация
  • У него есть абстрактный метод. Кроме того, он использует бетон
  • Нет ограничений для модификаторов метода абстрактного класса
  • Нет ограничений для модификаторов переменных абстрактного класса
  • Мы не можем объявить другие модификаторы, кроме абстрактных
  • Нет ограничений для инициализации переменных

Взято с сайта DurgaJobs

Давайте снова поработаем над этим вопросом:

Первое, что вам нужно знать, это то, что 1/1 и 1*1 дают одинаковые результаты, но это не означает, что умножение и деление одинаковы. Очевидно, у них хорошие отношения, но учтите, что вы оба разные.

Я укажу основные отличия, а остальное уже объяснили:

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

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

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

Следующие примеры демонстрируют это.

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

abstract class animals
{
    // They all love to eat. So let's implement them for everybody
    void eat()
    {
        System.out.println("Eating...");
    }
    // The make different sounds. They will provide their own implementation.
    abstract void sound();
}

class dog extends animals
{
    void sound()
    {
        System.out.println("Woof Woof");
    }
}

class cat extends animals
{
    void sound()
    {
        System.out.println("Meoww");
    }
}

Ниже приведена реализация интерфейса в Java:

interface Shape
{
    void display();
    double area();
}

class Rectangle implements Shape 
{
    int length, width;
    Rectangle(int length, int width)
    {
        this.length = length;
        this.width = width;
    }
    @Override
    public void display() 
    {
        System.out.println("****\n* *\n* *\n****"); 
    }
    @Override
    public double area() 
    {
        return (double)(length*width);
    }
} 

class Circle implements Shape 
{
    double pi = 3.14;
    int radius;
    Circle(int radius)
    {
        this.radius = radius;
    }
    @Override
    public void display() 
    {
        System.out.println("O"); // :P
    }
    @Override
    public double area() 
    { 
        return (double)((pi*radius*radius)/2);
    }
}

Несколько важных ключевых моментов в двух словах:

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

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

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

Это довольно просто на самом деле.

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

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

Абстрактный класс позволяет вам как объявлять (используя абстрактные методы), так и определять (используя полные реализации методов) поведение, которое должен иметь класс.

А обычный класс позволяет вам только определять, а не объявлять поведение / действия, которые должен иметь класс.

Одна последняя вещь,

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

Это означает, что наследование определенного поведения ограничено, чтобы разрешить только одно на класс... то есть, если вы хотели, чтобы класс, инкапсулирующий поведение из классов A,B и C, вам нужно было бы сделать следующее: класс A расширяет B, класс C расширяет A .. немного о способе иметь множественное наследование...

Интерфейсы с другой стороны, вы могли бы просто сделать: интерфейс C реализует A,B

Таким образом, в действительности Java поддерживает множественное наследование только в "объявленном поведении", то есть в интерфейсах, и только в единственном наследовании с определенным поведением... если только вы не выполните описанный мной способ...

Надеюсь, это имеет смысл.

Сравнение интерфейса с абстрактным классом неверно. Вместо этого должно быть два других сравнения: 1) интерфейс против класса и 2) абстрактный против финального класса.

Интерфейс против Класса

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

interface Package {
  String address();
}

Класс - это группа объектов, которые подчиняются договору. Например, я ящик из группы "Ящик" и подчиняюсь договору, требуемому Почтальоном. В то же время я подчиняюсь другим контрактам:

class Box implements Package, Property {
  @Override
  String address() {
    return "5th Street, New York, NY";
  }
  @Override
  Human owner() {
    // this method is part of another contract
  }
}

Аннотация против Финал

Абстрактный класс - это группа незавершенных объектов. Их нельзя использовать, потому что они пропускают некоторые части. Например, я - абстрактная коробка с поддержкой GPS- я знаю, как проверить свое положение на карте:

abstract class GpsBox implements Package {
  @Override
  public abstract String address();
  protected Coordinates whereAmI() {
    // connect to GPS and return my current position
  }
}

Этот класс, если он унаследован / расширен другим классом, может быть очень полезным. Но само по себе - это бесполезно, так как не может иметь объектов. Абстрактные классы могут быть элементами построения конечных классов.

Финальный класс - это группа законченных объектов, которые можно использовать, но нельзя изменить. Они точно знают, как работать и что делать. Например, я ящик, который всегда идет по адресу, указанному при его создании:

final class DirectBox implements Package {
  private final String to;
  public DirectBox(String addr) {
    this.to = addr;
  }
  @Override
  public String address() {
    return this.to;
  }
}

В большинстве языков, таких как Java или C++, возможно иметь только класс, ни абстрактный, ни окончательный. Такой класс может быть унаследован и может быть создан. Я не думаю, что это строго соответствует объектно-ориентированной парадигме.

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

Интерфейс: поверните (поверните налево, поверните направо)

Абстрактный класс: Колесо.

Класс: рулевое колесо, происходит от колеса, выставляет интерфейс поворота

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

Вкратце различия следующие:

Синтаксические различия между интерфейсом и абстрактным классом:

  1. Методы и члены абстрактного класса могут иметь любую видимость. Все методы интерфейса должны быть публичными. // больше не выполняется в Java 9
  2. Конкретный дочерний класс абстрактного класса должен определять все абстрактные методы. Абстрактный дочерний класс может иметь абстрактные методы. Интерфейс, расширяющий другой интерфейс, не должен обеспечивать реализацию по умолчанию для методов, унаследованных от родительского интерфейса.
  3. Дочерний класс может расширять только один класс. Интерфейс может расширять несколько интерфейсов. Класс может реализовывать несколько интерфейсов.
  4. Дочерний класс может определять абстрактные методы с такой же или менее ограниченной видимостью, тогда как класс, реализующий интерфейс, должен определять все методы интерфейса как общедоступные.
  5. Абстрактные классы могут иметь конструкторы, но не интерфейсы.
  6. Интерфейсы из Java 9 имеют частные статические методы.

В интерфейсах сейчас:

public static - поддерживается
public abstract - поддерживается
public default - поддерживается
private static - поддерживается
private abstract - ошибка компиляции
private default - ошибка компиляции
private - поддерживается

Разница лишь в том, что один может участвовать в множественном наследовании, а другой - нет.

Определение интерфейса со временем изменилось. Как вы думаете, интерфейс имеет только объявления методов и является просто контрактами? А как насчет статических конечных переменных и определения по умолчанию после Java 8?

Интерфейсы были введены в Java из-за проблемы алмаза с множественным наследованием, и именно это они и намерены делать.

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

См. Почему Java допускает статические конечные переменные в интерфейсах, если они предназначены только для контрактов?,

Я опаздываю на вечеринку на 10 лет, но хочу попытаться любым способом. Несколько дней назад написал примерно то же сообщение на Medium. Подумал выложить сюда.

tl;dr; Когда вы видите связь "Is A", используйте наследование / абстрактный класс. когда вы видите связь "имеет", создайте переменные-члены. Когда вы видите "зависит от внешнего поставщика", реализуйте (не наследуйте) интерфейс.

Вопрос для интервью: В чем разница между интерфейсом и абстрактным классом? А как вы решаете, когда что использовать? В основном я получаю один или все ответы ниже:Ответ 1: вы не можете создать объект абстрактного класса и интерфейсов.

ЗК (это мои инициалы): Вы не можете создать объект ни того, ни другого. Так что это не разница. Это сходство между интерфейсом и абстрактным классом. Встречный вопрос: почему вы не можете создать объект абстрактного класса или интерфейса?

Ответ 2: Абстрактные классы могут иметь тело функции как частичную реализацию / реализацию по умолчанию.

ЗК: Встречный вопрос: Итак, если я изменю его на чистый абстрактный класс, отмечу все виртуальные функции как абстрактные и не предоставлю реализации по умолчанию для какой-либо виртуальной функции. Сделало бы это абстрактные классы и интерфейсы одинаковыми? И могут ли они после этого использоваться как взаимозаменяемые?

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

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

Нарицательное: нарицательным это название дано € œin commonâ € к вещам того же класса или вида. Например, фрукты, животные, город, машина и т. Д.

Правильное Существительное: Правильное существительное имя объекта, места или вещи. Apple, Cat, New York, Honda Accord и др.

Автомобиль - это существительное нарицательное. А Honda Accord - это существительное собственное и, вероятно, составное существительное собственное, имя собственное, образованное двумя существительными.

Переходя к части UML. Вы должны быть знакомы со следующими отношениями:

  • Это
  • Имеет
  • Использует

Давайте рассмотрим следующие два предложения. - HondaAccord - это автомобиль? - У HondaAccord есть машина?

Какой из них звучит правильно? Простой английский и понимание. HondaAccord и Cars разделяют отношения типа "А". У Honda Accord нет машины. Это "машина". Honda Accord "имеет" музыкальный проигрыватель.

Когда два объекта разделяют отношение "Is A", это лучший кандидат на наследование. И имеет отношение - лучший кандидат для создания переменных-членов. После этого наш код выглядит так:

abstract class Car
{
   string color;
   int speed;
}
class HondaAccord : Car
{
   MusicPlayer musicPlayer;
}

Сейчас Honda не производит музыкальные плееры. По крайней мере, это не их основной бизнес.

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

Это делает Music Player идеальным кандидатом на роль интерфейса. Вам все равно, кто будет поддерживать его, если соединения работают нормально.

Вы можете заменить MusicPlayer LG на Sony или другим способом. И это ничего не изменит в Honda Accord.

Почему вы не можете создать объект из абстрактных классов?

Потому что вы не можете зайти в выставочный зал и сказать: "Дайте мне машину". Вам нужно будет указать имя собственное. Какая машина? Наверное, Honda Accord. И тогда торговый агент может вам что-нибудь дать.

Почему вы не можете создать объект интерфейса? Потому что нельзя зайти в выставочный зал и сказать: "Дайте мне контракт на музыкальный проигрыватель". Это не поможет. Интерфейсы существуют между потребителями и поставщиками только для облегчения соглашения. Что вы будете делать с копией договора? Музыка не воспроизводится.

Почему интерфейсы допускают множественное наследование?

Интерфейсы не наследуются. Реализованы интерфейсы. Интерфейс является кандидатом на взаимодействие с внешним миром. У Honda Accord есть интерфейс для заправки. Имеет интерфейсы для накачивания шин. И тот же шланг, которым накачивают футбольный мяч. Итак, новый код будет выглядеть следующим образом:

abstract class Car
{
    string color;
    int speed;
}
class HondaAccord : Car, IInflateAir, IRefueling
{
    MusicPlayer musicPlayer;
}

А по-английски будет звучать так: "Honda Accord - это автомобиль, который поддерживает накачивание шин и заправку".

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

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

Резюме

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

Какой использовать?

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

Следствие: обратное часто делается неправильно: при использовании вещи всегда старайтесь использовать самый общий класс / интерфейс, который вам действительно нужен. Другими словами, не объявляйте ваши переменные как ArrayList theList = new ArrayList() Если только у вас нет очень сильной зависимости от того, что он является списком массивов, и никакие другие типы списков не смогут его урезать. использование List theList = new ArrayList вместо или даже Collection theCollection = new ArrayList если факт, что это список, а не какой-либо другой тип коллекции, на самом деле не имеет значения.

На самом деле это не ответ на первоначальный вопрос, но как только вы получите ответ на разницу между ними, вы введете дилемму "когда использовать каждый": когда использовать интерфейсы или абстрактные классы? Когда использовать оба?

Я ограничил знание ООП, но видение интерфейсов как эквивалента прилагательного в грамматике до сих пор работало для меня (поправьте меня, если этот метод фальшивый!). Например, имена интерфейсов похожи на атрибуты или возможности, которые вы можете дать классу, и у класса может быть много из них: ISerializable, ICountable, IList, ICacheable, IHappy, ...

Вы можете найти четкую разницу между интерфейсом и абстрактным классом.

Интерфейс

  • Интерфейс содержит только абстрактные методы.
  • Заставить пользователей реализовывать все методы, когда реализует интерфейс.
  • Содержит только конечные и статические переменные.
  • Объявите, используя ключевое слово интерфейса.
  • Все методы интерфейса должны быть определены как публичные.
  • Интерфейс может расширяться или класс может реализовывать несколько других интерфейсов.

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

  • Абстрактный класс содержит абстрактные и неабстрактные методы.

  • Не заставляет пользователей реализовывать все методы при наследовании абстрактного класса.

  • Содержит все виды переменных, включая примитивные и не примитивные

  • Объявите, используя абстрактное ключевое слово.

  • Методы и члены абстрактного класса могут быть определены с любой видимостью.

  • Дочерний класс может расширять только один класс (абстрактный или конкретный).

Ключевые моменты:

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

Преимущество:

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

подробности смотрите здесь... http://pradeepatkari.wordpress.com/2014/11/20/interface-and-abstract-class-in-c-oops/

Кратчайший способ подвести итог это то, что interface является:

  1. Полностью абстрактный, кроме default а также static методы; в то время как у него есть определения (сигнатуры методов + реализации) для default а также static методы, он имеет только объявления (сигнатуры методов) для других методов.
  2. Подчиняется более слабым правилам, чем классы (класс может реализовать несколько interface с и interface может наследоваться от нескольких interface с). Все переменные неявно постоянны, указаны ли они как public static final или нет. Все участники неявно public указано ли таковое или нет.
  3. Обычно используется как гарантия того, что реализующий класс будет иметь указанные функции и / или будет совместим с любым другим классом, который реализует тот же интерфейс.

Между тем, abstract класс это:

  1. Везде от полностью абстрактного до полностью реализованного, с тенденцией иметь один или несколько abstract методы. Может содержать как объявления, так и определения, причем объявления помечаются как abstract,
  2. Полноценный класс и подчиняется правилам, которые управляют другими классами (может наследоваться только от одного класса), при условии, что он не может быть создан (потому что нет гарантии, что он полностью реализован). Может иметь непостоянные переменные-члены. Может реализовать контроль доступа членов, ограничивая членов как protected, private или личный пакет (не указан).
  3. Обычно используется либо для предоставления столько реализации, сколько может совместно использовать несколько подклассов, либо для предоставления столько реализации, сколько может предоставить программист.

Или, если мы хотим свести все это к одному предложению: interface это то, что имеет класс реализации, но abstract класс это то, что подкласс.

Различия между абстрактным классом и интерфейсом от имени реальной реализации.

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

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

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

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

Пример абстрактного класса:

 public abstract class DesireCar
  {

 //It is an abstract method that defines the prototype.
     public abstract void Color();

  // It is a default implementation of a Wheel method as all the desire cars have the same no. of wheels.   
 // and hence no need to define this in all the sub classes in this way it saves the code duplicasy     

  public void Wheel() {          

               Console.WriteLine("Car has four wheel");
                }
           }


    **Here is the sub classes:**

     public class DesireCar1 : DesireCar
        {
            public override void Color()
            {
                Console.WriteLine("This is a red color Desire car");
            }
        }

        public class DesireCar2 : DesireCar
        {
            public override void Color()
            {
                Console.WriteLine("This is a red white Desire car");
            }
        }

Пример интерфейса:

  public interface IShape
        {
          // Defines the prototype(template) 
            void Draw();
        }


  // All the sub classes follow the same template but implementation can be different.

    public class Circle : IShape
    {
        public void Draw()
        {
            Console.WriteLine("This is a Circle");
        }
    }

    public class Rectangle : IShape
    {
        public void Draw()
        {
            Console.WriteLine("This is a Rectangle");
        }
    }

Тема абстрактных классов и интерфейсов в основном касается семантики.

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

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

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

Например Formatter должны быть в состоянии format()что нибудь. Обычной семантикой для описания чего-то подобного было бы создание интерфейсаIFormatter с декларацией format()это действует как контракт. НоIFormatterне описывает, что что-то есть, а только то, что должно быть уметь. Общая семантика для описания того, чем что-то является на самом деле, - это создание класса. В этом случае мы создаем абстрактный класс... Итак, мы создаем абстрактный классFormatterкоторый реализует интерфейс. Это очень наглядный код, потому что теперь мы знаем, что у нас естьFormatter и теперь мы знаем, что каждый Formatter надо уметь делать.

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

Примечание. Это очень распространенный шаблон, при котором абстрактный класс реализует интерфейс.

Наследование используется для двух целей:

  • Позволить объекту рассматривать элементы данных родительского типа и реализации методов как свои собственные.

  • Разрешить использование ссылки на объекты одного типа кодом, который ожидает ссылку на объект супертипа.

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

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

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

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

Отличия

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

Сценарии использования

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

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

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

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

Однако у абстрактных классов могут быть реализованы методы и инициализированы переменные-члены.

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

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

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

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

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

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

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

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

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