В чем разница между интерфейсом и абстрактным классом? - PullRequest
1651 голосов
/ 16 декабря 2009

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

Ответы [ 34 ]

3 голосов
/ 03 сентября 2013

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

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

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

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

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

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

3 голосов
/ 29 января 2016

Кратчайший способ подвести итог: 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 - это то, что подкласс есть .

3 голосов
/ 15 декабря 2016

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

3 голосов
/ 19 января 2015

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

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

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

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

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

3 голосов
/ 24 августа 2017

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

Интерфейс

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

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

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

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

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

  • Объявите с помощью абстрактного ключевого слова.

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

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

2 голосов
/ 20 сентября 2016

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

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

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

2 голосов
/ 19 июня 2016

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

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

Резюме

  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 основное внимание уделяется тому, кто реализует * 1075. * это.

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

Примечание по Java 8 и методы по умолчанию

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

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

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

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

1 голос
/ 26 августа 2013

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

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

1 голос
/ 29 октября 2018

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

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

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

enter image description here

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

1 голос
/ 23 мая 2018

Простое, но эффективное объяснение абстрактного класса и интерфейса на php.net :

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

Интерфейс - это всегда соглашение или обещание. Когда класс говорит: «Я реализую интерфейс Y», он говорит: «Я обещаю иметь те же открытые методы, которые есть у любого объекта с интерфейсом Y».

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

Абстрактный класс является основой для другого объекта. Когда класс говорит «Я расширяю абстрактный класс Y», он говорит: «Я использую некоторые методы или свойства, уже определенные в этом другом классе с именем Y».

Итак, рассмотрим следующий PHP:

<?php
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...