Интерфейс против абстрактного класса (общий ОО)
Недавно у меня было два телефонных интервью, где меня спрашивали о различиях между интерфейсом и абстрактным классом. Я объяснил каждый их аспект, который мог придумать, но, похоже, они ждут, чтобы я упомянул что-то конкретное, и я не знаю, что это такое.
Исходя из своего опыта, я думаю, что это правда. Если я пропустил главное, пожалуйста, дайте мне знать.
Интерфейс:
Каждый метод, объявленный в интерфейсе, должен быть реализован в подклассе. В интерфейсе могут существовать только события, делегаты, свойства (C#) и методы. Класс может реализовывать несколько интерфейсов.
Абстрактный класс:
Только абстрактные методы должны быть реализованы подклассом. Класс Abstract может иметь нормальные методы с реализациями. Абстрактный класс также может иметь переменные класса, кроме событий, делегатов, свойств и методов. Класс может реализовать только один абстрактный класс только из-за отсутствия Multi-наследования в C#.
После всего этого интервьюер задал вопрос: "Что если бы у вас был класс Abstract только с абстрактными методами? Чем бы он отличался от интерфейса?" Я не знал ответа, но я думаю, что это наследство, как упомянуто выше, верно?
Другой интервьюер спросил меня, что если бы внутри интерфейса была переменная Public, как бы она отличалась от абстрактного класса? Я настаивал на том, чтобы внутри интерфейса не было публичной переменной. Я не знал, что он хотел услышать, но он тоже не был удовлетворен.
Смотрите также:
38 ответов
Хотя ваш вопрос указывает на то, что он относится к "общепринятым нормам", похоже, что он действительно фокусируется на использовании этих терминов в.NET
В.NET (аналогично для Java):
- интерфейсы могут не иметь состояния или реализации
- класс, который реализует интерфейс, должен обеспечивать реализацию всех методов этого интерфейса
- абстрактные классы могут содержать состояние (члены данных) и / или реализацию (методы)
- абстрактные классы могут наследоваться без реализации абстрактных методов (хотя такой производный класс сам является абстрактным)
- интерфейсы могут быть множественным наследованием, абстрактные классы - нет (это, вероятно, основная конкретная причина существования интерфейсов отдельно от абстрактных классов - они допускают реализацию множественного наследования, которая устраняет многие проблемы общего MI).
Как общие термины ОО, различия не обязательно четко определены. Например, есть программисты на C++, которые могут иметь схожие жесткие определения (интерфейсы являются строгим подмножеством абстрактных классов, которые не могут содержать реализацию), в то время как некоторые могут сказать, что абстрактный класс с некоторыми реализациями по умолчанию все еще является интерфейсом или что неабстрактный класс все еще может определять интерфейс.
Действительно, существует идиома C++, называемая не-виртуальным интерфейсом (NVI), где открытые методы - это не виртуальные методы, которые "подчиняются" частным виртуальным методам:
Как насчет аналогии: когда я был в ВВС, я прошел подготовку пилотов и стал пилотом ВВС США (ВВС США). В тот момент я не был квалифицирован, чтобы летать на чем-либо, и должен был посещать обучение по типу самолета После того, как я получил квалификацию, я был пилотом (абстрактный класс) и пилотом C-141 (конкретный класс). На одном из моих заданий мне дали дополнительную обязанность: офицер безопасности. Теперь я был еще пилотом и пилотом C-141, но я также выполнял обязанности сотрудника по безопасности (я реализовал, так сказать, ISafetyOfficer). Пилот не должен был быть офицером безопасности, другие люди тоже могли это сделать.
Все пилоты ВВС США должны следовать определенным правилам военно-воздушных сил, а все пилоты C-141 (или F-16, или T-38) являются "пилотами ВВС США". Любой может быть офицером безопасности. Итак, подведем итог:
- Пилот: абстрактный класс
- C-141 Pilot: класс бетона
- Сотрудник по безопасности: интерфейс
добавленное примечание: это должна была быть аналогия, помогающая объяснить концепцию, а не рекомендация по кодированию. Смотрите различные комментарии ниже, обсуждение интересно.
Я думаю, что ответ, который они ищут, - это принципиальное различие или философское отличие OPPS.
Наследование абстрактного класса используется, когда производный класс разделяет основные свойства и поведение абстрактного класса. Тип поведения, который на самом деле определяет класс.
С другой стороны, наследование интерфейса используется, когда классы имеют периферийное поведение, которое не обязательно определяет производный класс.
Например, Автомобиль и Грузовик имеют много основных свойств и поведения абстрактного класса Automobile, но они также имеют некоторое периферийное поведение, такое как Генерация выхлопа, которое разделяют даже не автомобильные классы, такие как Drillers или PowerGenerators, и не обязательно определяют Автомобиль или Грузовик. Таким образом, Car, Truck, Driller и PowerGenerator могут использовать один и тот же интерфейс IExhaust.
Коротко: Абстрактные классы используются для моделирования иерархии классов похожих классов (например, Animal может быть абстрактным классом, а Human, Lion, Tiger могут быть конкретными производными классами)
А ТАКЖЕ
Интерфейс используется для связи между 2 подобными / не похожими классами, которые не заботятся о типе класса, реализующего интерфейс (например, Высота может быть свойством интерфейса и может быть реализована человеком, зданием, деревом. Не имеет значения, можете ли вы есть, вы можете плавать, вы можете умереть или что-то еще.. это имеет значение только то, что вам нужно иметь высоту (реализация в вашем классе)).
Есть несколько других отличий -
Интерфейсы не могут иметь никаких конкретных реализаций. Абстрактные базовые классы могут. Это позволяет вам предоставлять конкретные реализации там. Это может позволить абстрактному базовому классу фактически предоставить более строгий контракт, тогда как интерфейс действительно только описывает, как используется класс. (Абстрактный базовый класс может иметь не виртуальные члены, определяющие поведение, что дает больше контроля автору базового класса.)
В одном классе может быть реализовано более одного интерфейса. Класс может быть производным только от одного абстрактного базового класса. Это допускает полиморфную иерархию с использованием интерфейсов, но не абстрактных базовых классов. Это также учитывает псевдо-мульти-наследование с использованием интерфейсов.
Абстрактные базовые классы могут быть изменены в v2+ без нарушения API. Изменения в интерфейсах разрушают изменения.
[C# /.NET Specific] Интерфейсы, в отличие от абстрактных базовых классов, могут применяться к типам значений (структурам). Структуры не могут наследоваться от абстрактных базовых классов. Это позволяет применять поведенческие контракты / рекомендации по использованию к типам значений.
наследование
Рассмотрим машину и автобус. Это два разных автомобиля. Но, тем не менее, они имеют некоторые общие свойства, такие как рулевое управление, тормоза, шестерни, двигатель и т. Д.
Таким образом, с концепцией наследования это можно представить следующим образом...
public class Vehicle {
private Driver driver;
private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
//You can define as many properties as you want here ...
}
Теперь велосипед...
public class Bicycle extends Vehicle {
//You define properties which are unique to bicycles here ...
private Pedal pedal;
}
И автомобиль...
public class Car extends Vehicle {
private Engine engine;
private Door[] doors;
}
Это все о наследовании. Мы используем их для классификации объектов на более простые формы Base и их потомков, как мы видели выше.
Абстрактные классы
Абстрактные классы являются неполными объектами. Чтобы понять это далее, давайте еще раз рассмотрим аналогию с автомобилем.
Автомобиль можно водить. Правильно? Но разные транспортные средства управляются по-разному... Например, вы не можете водить машину так же, как водите велосипед.
Итак, как представить функцию движения транспортного средства? Труднее проверить, что это за тип транспортного средства, и управлять им со своей функцией; вам придется менять класс водителя снова и снова при добавлении нового типа транспортного средства.
Здесь идет роль абстрактных классов и методов. Вы можете определить метод drive как абстрактный, чтобы сказать, что каждый наследующий потомок должен реализовать эту функцию.
Так что, если вы измените класс автомобиля...
//......Code of Vehicle Class
abstract public void drive();
//.....Code continues
Велосипед и Автомобиль также должны указать, как им управлять. В противном случае код не скомпилируется и выдается ошибка.
Короче говоря, абстрактный класс является частично неполным классом с некоторыми неполными функциями, которые наследующие потомки должны указывать свои собственные.
Интерфейсы Интерфейсы полностью неполные. У них нет никаких свойств. Они просто указывают на то, что наследующие дети способны что-то делать...
Предположим, у вас есть разные типы мобильных телефонов. У каждого из них есть разные способы выполнять разные функции; Пример: позвонить человеку. Производитель телефона указывает, как это сделать. Здесь мобильные телефоны могут набирать номер, то есть он может набирать номер. Давайте представим это как интерфейс.
public interface Dialable {
public void dial(Number n);
}
Здесь создатель набора номера определяет, как набрать номер. Вам просто нужно дать ему номер для набора.
// Makers define how exactly dialable work inside.
Dialable PHONE1 = new Dialable() {
public void dial(Number n) {
//Do the phone1's own way to dial a number
}
}
Dialable PHONE2 = new Dialable() {
public void dial(Number n) {
//Do the phone2's own way to dial a number
}
}
//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE1;
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
Таким образом, используя интерфейсы вместо абстрактных классов, разработчику функции, которая использует Dialable, не нужно беспокоиться о его свойствах. Пример: есть ли у него сенсорный экран или клавиатура, стационарный телефон или мобильный телефон. Вам просто нужно знать, можно ли набрать номер; наследует ли (или реализует) интерфейс Dialable.
И что более важно, если когда-нибудь вы переключите Dialable с другим
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
Вы можете быть уверены, что код по-прежнему работает отлично, потому что функция, которая использует набор номера, не зависит (и не может) зависеть от деталей, отличных от указанных в интерфейсе набора номера. Они оба реализуют интерфейс Dialable, и это единственное, о чем заботится функция.
Разработчики обычно используют интерфейсы для обеспечения взаимодействия (взаимозаменяемости) между объектами, поскольку они имеют общую функцию (точно так же, как вы можете перейти на стационарный или мобильный телефон, если вам просто нужно набрать номер). Короче говоря, интерфейсы - это гораздо более простая версия абстрактных классов без каких-либо свойств.
Также обратите внимание, что вы можете реализовать (наследовать) столько интерфейсов, сколько захотите, но вы можете расширять (наследовать) только один родительский класс.
Больше информации Абстрактные классы и интерфейсы
Если вы считаете, java
В качестве языка ООП для ответа на этот вопрос выпуск Java 8 приводит к тому, что часть содержимого в ответах выше устарела. Теперь интерфейс Java может иметь методы по умолчанию с конкретной реализацией.
Сайт Oracle предоставляет ключевые различия между interface
а также abstract
учебный класс.
Рассмотрите возможность использования абстрактных классов, если:
- Вы хотите поделиться кодом между несколькими тесно связанными классами.
- Вы ожидаете, что классы, которые расширяют ваш абстрактный класс, имеют много общих методов или полей или требуют модификаторов доступа, отличных от public (например, protected и private).
- Вы хотите объявить нестатические или не финальные поля.
Рассмотрите возможность использования интерфейсов, если:
- Вы ожидаете, что несвязанные классы будут реализовывать ваш интерфейс. Например, многие несвязанные объекты могут реализовать
Serializable
интерфейс. - Вы хотите указать поведение определенного типа данных, но не беспокоитесь о том, кто реализует его поведение.
- Вы хотите воспользоваться множественным наследованием типа.
Проще говоря, я хотел бы использовать
интерфейс: для реализации контракта несколькими несвязанными объектами
абстрактный класс: для реализации одинакового или разного поведения среди нескольких связанных объектов
Взгляните на пример кода, чтобы ясно понять вещи: как мне объяснить разницу между интерфейсом и абстрактным классом?
Эти ответы слишком длинные.
Интерфейсы предназначены для определения поведения.
Абстрактные классы предназначены для определения самой вещи, включая ее поведение. Вот почему мы иногда создаем абстрактный класс с некоторыми дополнительными свойствами, наследующими интерфейс.
Это также объясняет, почему Java поддерживает только одиночное наследование для классов, но не накладывает ограничений на интерфейсы. Потому что конкретный объект не может быть разными, но может иметь разное поведение.
Интервьюеры лают странное дерево. Для языков, таких как C# и Java, есть разница, но в других языках, таких как C++, нет. Теория ОО не различает их, а только синтаксис языка.
Абстрактный класс - это класс с реализацией и интерфейсом (чисто виртуальные методы), которые будут наследоваться. Интерфейсы обычно не имеют никакой реализации, а только чисто виртуальные функции.
В C# или Java абстрактный класс без какой-либо реализации отличается от интерфейса только синтаксисом, используемым для его наследования, и тем фактом, что вы можете наследовать только от одного.
Реализуя интерфейсы, вы получаете композицию (отношения "есть") вместо наследования (отношения "есть"). Это важный принцип, который нужно помнить, когда речь заходит о таких вещах, как шаблоны проектирования, где вам нужно использовать интерфейсы для получения композиции поведения вместо наследования.
С концептуальной точки зрения, сохранение реализации, правил, преимуществ и достижения любой цели программирования с использованием кого-либо или обоих, может или не может иметь код / данные / свойство, бла-бла, одиночное или множественное наследование, все в стороне
1- Абстрактный (или чистый абстрактный) класс предназначен для реализации иерархии. Если ваши бизнес-объекты выглядят несколько структурно схожими, представляя только родительско-дочерние (иерархические) отношения, то будут использоваться классы наследования / абстрактные. Если ваша бизнес-модель не имеет иерархии, тогда не следует использовать наследование (здесь я не говорю о логике программирования, например, некоторые шаблоны проектирования требуют наследования). Концептуально абстрактный класс - это метод реализации иерархии бизнес-модели в ООП, он не имеет ничего общего с интерфейсами, фактически сравнивать абстрактный класс с интерфейсом бессмысленно, так как оба концептуально являются совершенно разными вещами, в интервью его просят просто проверить Концепции, потому что они выглядят так, предоставляют несколько одинаковую функциональность, когда речь идет о реализации, и мы, программисты, обычно уделяем больше внимания кодированию. Имейте также в виду, что абстракция отличается от абстрактного класса.
2. Интерфейс - это контракт, полная бизнес-функциональность, представленная одним или несколькими наборами функций. Вот почему он реализован, а не наследуется. Бизнес-объект (часть иерархии или нет) может иметь любое количество полных бизнес-функций. Это не имеет ничего общего с абстрактными классами, означает наследование в целом. Например, человек может запустить, слон может выполнить, птица может выполнить и т.д., все эти объекты различной иерархии будут реализовывать интерфейс RUN или интерфейс EAT или SPEAK. Не входите в реализацию, поскольку вы можете реализовать ее как наличие абстрактных классов для каждого типа, реализующего эти интерфейсы. Объект любой иерархии может иметь функциональность (интерфейс), которая не имеет ничего общего с его иерархией.
Я полагаю, что интерфейсы не были изобретены для достижения множественного наследования или для демонстрации публичного поведения, и аналогично, чистые абстрактные классы не должны отменять интерфейсы, но интерфейс - это функциональность, которую может выполнять объект (через функции этого интерфейса), а абстрактный класс представляет родительский элемент иерархии для создания дочерних элементов, имеющих базовую структуру (свойство + функциональность) родительского элемента
Когда вас спрашивают о разнице, это на самом деле концептуальное различие, а не различие в реализации для конкретного языка, если не задано явно.
Я полагаю, что оба интервьюера ожидали однозначного различия между этими двумя, а когда вы потерпели неудачу, они пытались подтолкнуть вас к этому различию, внедрив ОДНОГО как ДРУГОЕ
Что если у вас есть класс Abstract только с абстрактными методами?
Я объясню детали глубины интерфейса и абстрактного класса. Если вы знаете обзор интерфейса и абстрактного класса, то сначала у вас возникнет вопрос, когда нам следует использовать интерфейс и когда мы должны использовать абстрактный класс. Поэтому, пожалуйста, проверьте ниже объяснение интерфейса и абстрактного класса.
Когда мы должны использовать интерфейс?
если вы не знаете о реализации, просто у нас есть спецификация требований, то мы идем с интерфейсом
Когда мы должны использовать абстрактный класс?
если вы знаете реализацию, но не полностью (частично реализацию), тогда мы идем с классом Abstract.
Интерфейс
каждый метод по умолчанию открытый интерфейс означает, что интерфейс на 100% чистый.
Аннотация
может иметь метод Concrete и метод Abstract, то есть метод Concrete, имеющий реализацию в классе Abstract. Абстрактный класс - это класс, который объявлен как абстрактный - он может включать или не включать абстрактные методы.
Интерфейс
Мы не можем объявить интерфейс как частный, защищенный
В. Почему мы не объявляем интерфейс закрытым и защищенным?
Потому что по умолчанию метод интерфейса является публичным абстрактным, поэтому мы не объявляем интерфейс закрытым и защищенным.
Метод интерфейса
также мы не можем объявить интерфейс как закрытый, защищенный, окончательный, статический, синхронизированный, нативный.....Я приведу причину: почему мы не объявляем синхронизированный метод, потому что мы не можем создать объект интерфейса и синхронизировать, это работа над объектом, и причина того, что мы не объявляем синхронизированный метод, концепция переходного процесса также не применима, потому что временная работа с синхронизированной.
Аннотация
мы с радостью используем публичную, приватную финальную статическую.... означает, что никакие ограничения не применяются в абстрактном виде.
Интерфейс
Переменные объявляются в интерфейсе как открытый статический финал по умолчанию, поэтому мы также не объявляем переменную как частную защищенную.
Модификатор volatile также не применяется в интерфейсе, потому что переменная интерфейса по умолчанию является общедоступной статической конечной и конечной переменными. Вы не можете изменить значение, если оно присваивает значение переменной, а после объявления переменной в интерфейсе необходимо назначить переменную.
И изменчивая переменная это держать изменения, так что это опп. в конечном итоге это причина того, что мы не используем переменную volatile в интерфейсе.
Аннотация
Абстрактная переменная не нуждается в объявлении public static final.
Я надеюсь, что эта статья полезна.
Для.Net,
Ваш ответ Второму интервьюеру - также ответ на первый... Абстрактные классы могут иметь реализацию, И состояние, интерфейсы не могут...
РЕДАКТИРОВАТЬ: С другой стороны, я бы даже не использовал фразу "подкласс" (или фразу "наследование") для описания классов, которые "определены для реализации" интерфейса. Для меня интерфейс - это определение контракта, которому должен соответствовать класс, если он был определен для "реализации" этого интерфейса. Это ничего не наследует... Вы должны сами все добавить, явно.
Интерфейс: должен использоваться, если вы хотите наложить правило на компоненты, которые могут или не могут быть связаны друг с другом
Плюсы:
- Позволяет множественное наследование
- Обеспечивает абстракцию, не раскрывая, какой именно тип объекта используется в контексте
- обеспечивает согласованность путем конкретной подписи контракта
Минусы:
- Необходимо выполнить все контракты, определенные
- Не может иметь переменных или делегатов
- Однажды определенный не может быть изменен без нарушения всех классов
Абстрактный класс: должен использоваться там, где вы хотите иметь базовое или стандартное поведение или реализацию для компонентов, связанных друг с другом
Плюсы:
- Быстрее, чем интерфейс
- Имеет гибкость в реализации (вы можете реализовать ее полностью или частично)
- Может быть легко изменено, не нарушая производные классы
Минусы:
- Не может быть создан
- Не поддерживает множественное наследование
Я думаю, что им не понравился ваш ответ, потому что вы дали технические отличия вместо конструктивных. Вопрос для меня как вопрос тролля. На самом деле интерфейсы и абстрактные классы имеют совершенно другую природу, поэтому вы не можете их реально сравнить. Я дам вам свое видение роли интерфейса и роли абстрактного класса.
Интерфейс: используется для обеспечения контракта и создания слабой связи между классами, чтобы иметь более поддерживаемое, масштабируемое и тестируемое приложение.
абстрактный класс: используется только для разложения некоторого кода между классами с одинаковой ответственностью. Обратите внимание, что это является основной причиной, по которой множественное наследование является плохой вещью в ООП, поскольку класс не должен обрабатывать многие обязанности (вместо этого используйте композицию).
Таким образом, интерфейсы играют реальную архитектурную роль, в то время как абстрактные классы - это почти только деталь реализации (если вы, конечно, используете их правильно).
- Интерфейс:
- Мы не реализуем (или не определяем) методы, мы делаем это в производных классах.
- Мы не объявляем переменные-члены в интерфейсах.
- Интерфейсы выражают отношения HAS-A. Это означает, что они являются маской объектов.
- Абстрактный класс:
- Мы можем объявлять и определять методы в абстрактном классе.
- Мы скрываем конструкторы этого. Это означает, что нет никакого объекта, созданного из этого непосредственно.
- Абстрактный класс может содержать переменные-члены.
- Производные классы наследуются от абстрактного класса, что означает, что объекты из производных классов не маскируются, а наследуются от абстрактного класса. Отношения в этом случае IS-A.
Это мое мнение.
After all that, the interviewer came up with the question "What if you had an
Abstract class with only abstract methods? How would that be different
from an interface?"
В документах четко сказано, что если абстрактный класс содержит только объявления абстрактных методов, он должен быть объявлен как интерфейс.
An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?
Переменные в интерфейсах по умолчанию являются общедоступными static и final. Вопрос может быть сформулирован так, как если бы все переменные в абстрактном классе были публичными? Ну, они все еще могут быть не статичными и не финальными в отличие от переменных в интерфейсах.
Наконец, я бы добавил еще один момент к упомянутым выше - абстрактные классы все еще являются классами и попадают в одно дерево наследования, тогда как интерфейсы могут присутствовать в множественном наследовании.
Скопировано из CLR через C# Джеффри Рихтером...
Я часто слышу вопрос: "Должен ли я проектировать базовый тип или интерфейс?" Ответ не всегда однозначен.
Вот несколько рекомендаций, которые могут вам помочь:
■■ Соотношение IS-A и CAN-DO Тип может наследовать только одну реализацию. Если производный тип не может требовать отношения IS-A с базовым типом, не используйте базовый тип; использовать интерфейс. Интерфейсы подразумевают связь CAN-DO. Если кажется, что функциональность CAN-DO относится к различным типам объектов, используйте интерфейс. Например, тип может преобразовывать свои экземпляры в другой тип (IConvertible), тип может сериализовать свой экземпляр (ISerializable) и т. Д. Обратите внимание, что типы значений должны быть получены из System.ValueType, и, следовательно, они не могут быть получены из произвольного базового класса. В этом случае вы должны использовать отношение CAN-DO и определить интерфейс.
■■ Простота использования. Как разработчик, вам, как правило, легче определить новый тип, производный от базового типа, чем реализовать все методы интерфейса. Базовый тип может обеспечивать большую функциональность, поэтому производный тип, вероятно, нуждается лишь в относительно небольших модификациях своего поведения. Если вы предоставляете интерфейс, новый тип должен реализовывать все элементы.
■■ Последовательная реализация Независимо от того, насколько хорошо задокументирован контракт интерфейса, очень маловероятно, что каждый будет выполнять контракт на 100 процентов правильно. Фактически, COM страдает от этой самой проблемы, поэтому некоторые COM-объекты корректно работают только с Microsoft Word или Windows Internet Explorer. Предоставляя базовый тип с хорошей реализацией по умолчанию, вы начинаете с использования типа, который работает и хорошо протестирован; затем вы можете изменить детали, которые нуждаются в модификации.
■■ Управление версиями Если вы добавляете метод к базовому типу, производный тип наследует новый метод, вы начинаете с использования работающего типа, и исходный код пользователя даже не нужно перекомпилировать. Добавление нового члена в интерфейс заставляет наследника интерфейса изменить его исходный код и перекомпилировать.
Разница между Java-интерфейсом и абстрактным классом
Основное отличие заключается в том, что методы интерфейса Java неявно абстрактны и не могут иметь реализации. Абстрактный класс Java может иметь методы экземпляров, которые реализуют поведение по умолчанию.
Переменные, объявленные в интерфейсе Java, по умолчанию являются окончательными. Абстрактный класс может содержать неконечные переменные.
Члены интерфейса Java являются общедоступными по умолчанию. Абстрактный класс Java может иметь обычные разновидности членов класса, такие как private, protected и т. Д.
Java-интерфейс должен быть реализован с использованием ключевого слова "Implements"; Абстрактный класс Java должен быть расширен с использованием ключевого слова "extends".
Интерфейс может расширять только другой интерфейс Java, абстрактный класс может расширять другой класс Java и реализовывать несколько интерфейсов Java.
Класс Java может реализовывать несколько интерфейсов, но он может расширять только один абстрактный класс.
Интерфейс абсолютно абстрактный и не может быть создан; Абстрактный класс Java также не может быть создан, но может быть вызван, если существует main().
По сравнению с абстрактными Java-классами, Java-интерфейсы медленны, так как требуют дополнительной косвенности.
Tl ;dr; Когда вы видите связь "Is A", используйте наследование / абстрактный класс. когда вы видите связь "имеет", создайте переменные-члены. Когда вы видите "зависит от внешнего поставщика", реализуйте (не наследуйте) интерфейс.
Вопрос для собеседования: в чем разница между интерфейсом и абстрактным классом? А как вы решаете, когда что использовать? В основном я получаю один или все ответы ниже: Ответ 1: вы не можете создать объект абстрактного класса и интерфейсов.
ЗК (это мои инициалы): Вы не можете создать объект ни того, ни другого. Так что это не разница. Это сходство между интерфейсом и абстрактным классом. Встречный вопрос: почему вы не можете создать объект абстрактного класса или интерфейса?
Ответ 2: Абстрактные классы могут иметь тело функции как частичную реализацию / реализацию по умолчанию.
ЗК: Встречный вопрос: Итак, если я изменю его на чистый абстрактный класс, отмечу все виртуальные функции как абстрактные и не предоставлю реализацию по умолчанию для какой-либо виртуальной функции. Сделало бы это абстрактные классы и интерфейсы одинаковыми? И могут ли они после этого использоваться как взаимозаменяемые?
Ответ 3. Интерфейсы допускают множественное наследование, а абстрактные классы - нет.
ЗК: Встречный вопрос: действительно ли вы наследуете интерфейс? или вы просто реализуете интерфейс и наследуете от абстрактного класса? В чем разница между реализацией и наследованием? Эти встречные вопросы сбивают кандидатов с толку и заставляют многих почесать голову или просто перейти к следующему вопросу. Это заставляет меня думать, что людям нужна помощь с этими основными строительными блоками объектно-ориентированного программирования. Ответ на исходный вопрос и все встречные вопросы можно найти на английском языке и в UML. Вы должны знать, по крайней мере, ниже, чтобы лучше понять эти две конструкции.
Имя нарицательное: Существительное нарицательное - это имя, данное "в общем" вещам одного и того же класса или вида. Например, фрукты, животные, город, машина и т. Д.
Существительное собственное: имя собственное - это имя объекта, места или вещи. 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 - это автомобиль, который поддерживает накачивание шин и заправку".
Интерфейс определяет контракт на услугу или набор услуг. Они обеспечивают полиморфизм по горизонтали в том смысле, что два совершенно не связанных между собой класса могут реализовывать один и тот же интерфейс, но использоваться взаимозаменяемо в качестве параметра типа интерфейса, который они реализуют, так как оба класса обещали удовлетворить набор услуг, определенный интерфейсом. Интерфейсы не предоставляют подробности реализации.
Абстрактный класс определяет базовую структуру для своих подклассов и, возможно, частичную реализацию. Абстрактные классы обеспечивают полиморфизм вертикальным, но направленным образом, так что любой класс, который наследует абстрактный класс, может рассматриваться как экземпляр этого абстрактного класса, но не наоборот. Абстрактные классы могут и часто содержат детали реализации, но не могут быть созданы сами по себе - только их подклассы могут быть "обновлены".
Заметьте, C# также допускает наследование интерфейса.
В большинстве ответов основное внимание уделяется техническому различию между абстрактным классом и интерфейсом, но, поскольку технически интерфейс по сути является своего рода абстрактным классом (класс без каких-либо данных или реализации), я думаю, что концептуальное различие гораздо интереснее, и это может быть интервьюеры после.
Интерфейс - это соглашение. В нем указано: "так мы будем разговаривать друг с другом". Он не может иметь никакой реализации, потому что он не должен иметь никакой реализации. Это контракт. Это как .h
заголовочные файлы на C.
Абстрактный класс является неполной реализацией. Класс может реализовывать или не реализовывать интерфейс, а абстрактный класс не должен реализовывать его полностью. Абстрактный класс без какой-либо реализации бесполезен, но абсолютно легален.
По сути, любой класс, абстрактный или нет, - это то, чем он является, а интерфейс - как вы его используете. Например: Animal
может быть абстрактным классом, реализующим некоторые основные метаболические функции и определяющим абстрактные методы для дыхания и передвижения без предоставления реализации, потому что он не знает, должен ли он дышать через жабры или легкие, а также летать, плавать, ходить или ползать. Mount
с другой стороны, это может быть интерфейс, который определяет, что вы можете ездить на животном, не зная, что это за животное (или вообще это животное!).
Тот факт, что за кулисами интерфейс является в основном абстрактным классом с использованием только абстрактных методов, не имеет значения. Концептуально они исполняют совершенно разные роли.
Поскольку вы, возможно, получили теоретические знания от экспертов, я не буду тратить много слов на повторение всего этого здесь, а позвольте мне объяснить на простом примере, где мы можем использовать / не использовать Interface
а также Abstract class
,
Предположим, вы разрабатываете приложение, чтобы перечислить все функции автомобилей. В разных точках вам необходимо общее наследование, так как некоторые свойства, такие как DigitalFuelMeter, кондиционер, регулировка сиденья и т. Д., Являются общими для всех автомобилей. Кроме того, нам нужно наследование только для некоторых классов, поскольку некоторые свойства, такие как тормозная система (ABS,EBD), применимы только для некоторых автомобилей.
Нижеследующий класс выступает в качестве базового класса для всех автомобилей:
public class Cars
{
public string DigitalFuelMeter()
{
return "I have DigitalFuelMeter";
}
public string AirCondition()
{
return "I have AC";
}
public string SeatAdjust()
{
return "I can Adjust seat";
}
}
Представьте, что у нас есть отдельный класс для каждой машины.
public class Alto : Cars
{
// Have all the features of Car class
}
public class Verna : Cars
{
// Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars
}
public class Cruze : Cars
{
// Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars
}
Предположим, нам нужен метод наследования технологии торможения для автомобилей Verna и Cruze (неприменимо для Alto). Хотя оба используют технологию торможения, "технология" отличается. Итак, мы создаем абстрактный класс, в котором метод будет объявлен как Abstract, и он должен быть реализован в его дочерних классах.
public abstract class Brake
{
public abstract string GetBrakeTechnology();
}
Теперь мы пытаемся унаследовать от этого абстрактного класса, и тип системы торможения реализован в Verna и Cruze:
public class Verna : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
Видите проблему в двух вышеупомянутых классах? Они наследуются от нескольких классов, которые C#.Net не позволяет, хотя метод реализован в дочерних элементах. Здесь приходит необходимость интерфейса.
interface IBrakeTechnology
{
string GetBrakeTechnology();
}
И реализация приведена ниже:
public class Verna : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
Теперь Verna и Cruze могут добиться множественного наследования с помощью собственных технологий торможения с помощью интерфейса.
Абстрактный класс и разница в интерфейсе:
- Абстрактный класс может иметь абстрактные и неабстрактные методы, а интерфейс может иметь только абстрактные методы.
- Абстрактный класс не поддерживает множественное наследование. Интерфейс поддерживает множественное наследование.
- Абстрактный класс может иметь конечные, не финальные, статические и нестатические переменные, а интерфейс имеет только статические и конечные переменные.
- Абстрактный класс может иметь статические методы, метод main и конструктор, а интерфейс не может иметь статические методы, метод main или конструктор.
- Абстрактный класс может обеспечить реализацию интерфейса, а интерфейс не может обеспечить реализацию абстрактного класса.
- Ключевое слово abstract используется для объявления абстрактного класса. Ключевое слово interface используется для объявления интерфейса.
- Абстрактный класс достигает частичной абстракции (от 0 до 100%), потому что в абстрактном классе есть неабстрактные методы, тогда как интерфейс достигает полной абстракции (100%).
Интерфейсы - это легкий способ реализации определенного поведения. Это один из способов думать.
1) Интерфейс можно рассматривать как чистый абстрактный класс, он такой же, но, несмотря на это, не то же самое для реализации интерфейса и наследования от абстрактного класса. Когда вы наследуете от этого чистого абстрактного класса, вы определяете иерархию -> наследование, если вы реализуете интерфейс, которым вы не являетесь, и вы можете реализовать столько интерфейсов, сколько захотите, но вы можете наследовать только от одного класса.
2) Вы можете определить свойство в интерфейсе, поэтому класс, реализующий этот интерфейс, должен иметь это свойство.
Например:
public interface IVariable
{
string name {get; set;}
}
Класс, реализующий этот интерфейс, должен иметь такое свойство.
Хотя этот вопрос довольно старый, я хотел бы добавить еще один момент в пользу интерфейсов:
Интерфейсы могут быть внедрены с использованием любых инструментов Dependency Injection, в то время как внедрение класса Abstract поддерживается очень немногими.
Конечно, важно понимать поведение интерфейса и абстрактного класса в ООП (и как языки их обрабатывают), но я думаю, что также важно понимать, что именно означает каждый термин. Можете ли вы представить себе if
Команда не работает точно так же, как значение термина? Кроме того, на самом деле некоторые языки сокращают, даже больше, различия между интерфейсом и абстрактным... если случайно однажды два термина работают почти одинаково, по крайней мере, вы можете сами определить, где (и почему) должен быть любой из них. используется для.
Если вы читаете некоторые словари и другие шрифты, вы можете найти разные значения для одного и того же термина, но с некоторыми общими определениями. Я думаю, что эти два значения, которые я нашел на этом сайте, действительно, действительно хороши и подходят.
Интерфейс:
Вещи или обстоятельства, которые позволяют отдельным и иногда несовместимым элементам эффективно координировать действия.
Аннотация:
Нечто, которое концентрирует в себе основные качества чего-то более обширного или более общего или нескольких вещей; сущность.
Пример:
Вы купили машину, и ей нужно топливо.
Ваша модель автомобиля XYZ
жанра ABC
Таким образом, это конкретный автомобиль, конкретный экземпляр автомобиля. Автомобиль не настоящий объект. Фактически, это абстрактный набор стандартов (качеств) для создания конкретного объекта. Короче говоря, Car - это абстрактный класс, это "то, что концентрирует в себе основные качества чего-то более обширного или более общего".
Единственное топливо, которое соответствует спецификации автомобиля, должно использоваться для заполнения бака автомобиля. На самом деле, ничто не может ограничить вас в заправке топлива, но двигатель будет работать правильно только с указанным топливом, поэтому лучше следовать его требованиям. В требованиях говорится, что он принимает, как и другие автомобили того же жанра ABC
, стандартный набор топлива.
В объектно-ориентированном виде, топливо для жанра ABC
не должен быть объявлен как класс, потому что нет никакого конкретного топлива для определенного жанра автомобиля там. Несмотря на то, что ваш автомобиль может принимать абстрактный класс "Fuel" или "AutularFuel", вы должны помнить, что только некоторые из существующих видов топлива для автомобилей соответствуют спецификации, которые соответствуют требованиям, изложенным в руководстве по эксплуатации вашего автомобиля. Короче говоря, они должны реализовать интерфейс ABCGenreFuel
, который "... позволяет отдельным и иногда несовместимым элементам эффективно координировать".
добавление
Кроме того, я думаю, вы должны иметь в виду значение термина "класс", который (с того же сайта, о котором упоминалось ранее):
Учебный класс:
Количество людей или вещей, рассматриваемых как формирующие группу по причине общих признаков, характеристик, качеств или черт характера; Добрый;
Таким образом, класс (или абстрактный класс) должен представлять не только общие атрибуты (например, интерфейс), но и какую-то группу с общими атрибутами. Интерфейс не должен представлять вид. Он должен представлять общие атрибуты. Таким образом, я думаю, что классы и абстрактные классы могут использоваться для представления вещей, которые не должны часто менять свои аспекты, например, человек, являющийся млекопитающим, потому что он представляет некоторые виды. Виды не должны менять себя так часто.
Из другого моего ответа, в основном касающегося, когда использовать один против другого:
По моему опыту, интерфейсы лучше всего использовать, когда у вас есть несколько классов, каждый из которых должен отвечать на один и тот же метод или методы, чтобы их можно было использовать взаимозаменяемо другим кодом, который будет написан для общего интерфейса этих классов. Лучше всего использовать интерфейс, когда протокол важен, но базовая логика может отличаться для каждого класса. Если вы иначе дублируете логику, рассмотрите абстрактные классы или стандартное наследование классов.
Answer to the second question: public
переменная, определенная в interface
является static final
by default while the public
переменная в abstract
class is an instance variable.