В едно от моите интервюта ме помолиха да обясня разликата между интерфейс и абстрактен клас.
Ето моя отговор:
Методите на интерфейс на Java са имплицитно абстрактни и не могат да имат имплементации. Един абстрактен Java клас може да има инстанционни методи, които имплементират поведение по подразбиране.
Променливите, декларирани в Java интерфейс, по подразбиране са окончателни. Един може да съдържа променливи, които не са окончателни.
Членовете на Java интерфейс са публични по подразбиране. Един абстрактен Java клас може да има обичайните видове членове на класа като private, protected и т.н.
Един Java интерфейс трябва да бъде имплементиран с помощта на ключовата дума "implements"; A Java абстрактен клас трябва да бъде разширен с помощта на ключовата дума "extends".
Един интерфейс може да разширява само друг Java интерфейс, а един абстрактен клас може да разширява друг Java клас и да имплементира няколко Java интерфейса.
Един Java клас може да имплементира множество интерфейси, но може да разширява само един абстрактен клас.
Интервюиращият обаче не беше доволен и ми каза, че това описание представлява "книжни знания".
Той ме помоли за по-практичен отговор, в който да обясня кога бих избрал абстрактен клас вместо интерфейс, като използвам практически примери.
Къде сбърках?
Нищо не е съвършено в този свят. Може би са очаквали по-скоро практичен подход.
Но след вашето обяснение бихте могли да добавите тези редове с малко по-различен подход.
Интерфейсите са правила (правила, защото трябва да им дадете реализация, която не можете да пренебрегнете или да избегнете, така че те се налагат като правила), които работят като документ за общо разбиране между различните екипи при разработването на софтуер.
Интерфейсите дават представа какво трябва да се направи, но не и как ще се направи. Така че реализацията зависи изцяло от разработчика, който следва дадените правила (т.е. дадените сигнатури на методите).
Абстрактните класове могат да съдържат абстрактни декларации, конкретни имплементации или и двете.
Абстрактните декларации са като правила, които трябва да се спазват, а конкретните имплементации са като указания (можете да ги използвате така, както са, или да ги пренебрегнете, като ги надстроите и имплементирате свои собствени).
Освен това кои методи с една и съща сигнатура могат да променят поведението си в различен контекст, се предоставят като декларации на интерфейса като правила за съответното имплементиране в различен контекст.
Едит: Java 8 улеснява дефинирането на методи по подразбиране и статични методи в интерфейса.
public interface SomeInterfaceOne {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
}
}
Сега, когато даден клас имплементира SomeInterface, не е задължително да се предоставя имплементация за методите по подразбиране на интерфейса.
Ако имаме друг интерфейс със следните методи:
public interface SomeInterfaceTwo {
void usualAbstractMethod(String inputString);
default void defaultMethod(String inputString){
System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
}
}
Java не позволява разширяване на няколко класа, защото това води до "Диамантен проблем ", при който компилаторът не може да реши кой метод на суперкласа да използва. С методите по подразбиране проблемът с диаманта ще възникне и за интерфейсите. Защото ако един клас имплементира едновременно
SomeInterfaceOne and SomeInterfaceTwo
и не имплементира общия метод по подразбиране, компилаторът не може да реши кой от тях да избере. За да се избегне този проблем, в java 8 е задължително да се имплементират общи методи по подразбиране на различни интерфейси. Ако някой клас имплементира и двата гореспоменати интерфейса, той трябва да предостави имплементация за метода defaultMethod(), в противен случай компилаторът ще хвърли грешка по време на компилация.
Обяснението ти изглежда прилично, но може би изглежда така, сякаш си го чел от учебник? :-/
Това, което ме притеснява повече, е доколко солиден беше примерът ти? Направихте ли си труда да включите почти всички разлики между абстракциите и интерфейсите?
Лично аз бих предложил този линк: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE
за изчерпателен списък на разликите..
Надявам се, че това ще помогне на вас и на всички други читатели в бъдещите им интервюта
Интерфейсът е "договор", при който класът, който изпълнява договора, обещава да изпълни методите. Пример, в който трябваше да напиша интерфейс вместо клас, беше, когато надграждах една игра от 2D в 3D. Трябваше да създам интерфейс, за да споделям класове между 2D и 3D версията на играта.
package adventure;
import java.awt.*;
public interface Playable {
public void playSound(String s);
public Image loadPicture(String s);
}
Тогава мога да имплементирам методите в зависимост от средата, като същевременно мога да извикам тези методи от обект, който не знае коя версия на играта се зарежда.
публичен клас Adventure extends JFrame implements Playable
публичен клас Dungeon3D extends SimpleApplication implements Playable
публичен клас Main extends SimpleApplication имплементира AnimEventListener, ActionListener, Playable
Обикновено в света на играта светът може да бъде абстрактен клас, който изпълнява методи на играта:
public abstract class World...
public Playable owner;
public Playable getOwner() {
return owner;
}
public void setOwner(Playable owner) {
this.owner = owner;
}