Подтвердить что ты не робот

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

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

Здесь мой ответ:

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

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

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

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

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

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

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

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

Где я ошибся?

4b9b3361

Ответ 1

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

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

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

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

Но что, если encryptPassword() не зависит от базы данных, и это одинаково для каждого класса? Тогда это не было бы хорошим подходом.

Вместо этого рассмотрите этот подход:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

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

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

Ответ 2

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

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

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

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

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

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

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

Изменить: Java 8 облегчает определение стандартных и статических методов в интерфейсе.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

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

Если у нас есть другой интерфейс со следующими методами:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java не позволяет расширять несколько классов, потому что это приводит к проблеме "Diamond", когда компилятор не может решить, какой метод суперкласса использовать. С помощью методов по умолчанию проблема с алмазами будет возникать и для интерфейсов. Потому что, если класс реализует оба

SomeInterfaceOne and SomeInterfaceTwo

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

Рассмотрим класс оплаты. Оплата может быть произведена различными способами, такими как PayPal, кредитная карта и т.д. Таким образом, мы обычно берем оплату как наш интерфейс, который содержит метод makePayment(), а CreditCard и PayPal - два класса реализации.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

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

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

Рассмотрим следующий пример:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

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

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

Ответ 5

Разница между классом Abstact и интерфейсом

  • Абстрактные классы и интерфейсы в Java 8
  • Концептуальная разница:

Параметры интерфейса по умолчанию в Java 8

  • Что такое метод по умолчанию?
  • Ошибка компиляции метода ForEach с использованием метода по умолчанию
  • Метод устранения неполадок по умолчанию и множественные проблемы с наследованием.
  • Важные моменты о методах по умолчанию для интерфейса Java:

Статический метод интерфейса Java

  • Статический метод интерфейса Java, пример кода, метод static method vs default
  • Важные моменты о статическом методе Java-интерфейса:

Функциональные интерфейсы Java



Абстрактные классы и интерфейсы в Java 8

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

После введения метода по умолчанию кажется, что интерфейсы и абстрактные классы одинаковы. Тем не менее, они все еще отличаются концепцией в Java 8.

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

Концептуальная разница:

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

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

Параметры интерфейса по умолчанию в Java 8

Java 8 вводит новую функцию Default Method" или (Defender methods), которая позволяет разработчику добавлять новые методы в интерфейсы, не нарушая существующая реализация этого интерфейса. Он обеспечивает гибкость, позволяющую реализовать реализацию интерфейса, которая будет использоваться по умолчанию в ситуации, когда конкретный класс не может обеспечить реализацию для этого метода.

Рассмотрим небольшой пример, чтобы понять, как он работает:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

Следующий класс будет успешно скомпилирован в Java JDK 8,

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

Если вы создаете экземпляр OldInterfaceImpl:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print "New default method add in interface"
obj.newDefaultMethod(); 

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

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

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

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

Когда мы расширяем интерфейс, который содержит метод по умолчанию, мы можем выполнить следующее,

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

Ошибка компиляции метода ForEach с использованием метода по умолчанию

Для Java 8 коллекции JDK были расширены и метод forEach добавлен ко всей коллекции (которая работает совместно с lambdas). С обычным способом код выглядит как ниже,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

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

Интерфейс Iterable с методом по умолчанию приведен ниже,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Тот же механизм был использован для добавления Stream в интерфейсе JDK без нарушения реализующих классов.


Метод по умолчанию и множественные проблемы неоднозначности наследования

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

Рассмотрим ниже пример,

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

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

java: класс Impl наследует несвязанные значения по умолчанию для defaultMethod() из типы InterfaceA и InterfaceB

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

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

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

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

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

Важные моменты о стандартном методе интерфейса Java:

  • По умолчанию методы интерфейса Java помогут нам расширить интерфейсы, не опасаясь сломать классы реализации.
  • Методы интерфейса Java по умолчанию имеют ограничения на различия между интерфейсами и абстрактными классами.
  • Методы по умолчанию интерфейса Java 8 помогут нам избежать классов утилиты, например, весь метод класса Collections может быть предоставлен в самих интерфейсах.
  • Методы по умолчанию для интерфейса Java помогут нам в устранении базовых классов реализации, мы можем обеспечить реализацию по умолчанию, и классы реализации могут выбрать, какой из них следует переопределить.
  • Одной из основных причин внедрения методов по умолчанию в интерфейсах является расширение API Collections в Java 8 для поддержки лямбда-выражений.
  • Если какой-либо класс в иерархии имеет метод с одинаковой сигнатурой, методы по умолчанию становятся неактуальными. Метод по умолчанию не может переопределить метод из java.lang.Object. Обоснование очень просто, потому что Object является базовым классом для всех классов java. Поэтому, даже если у нас есть методы класса Object, определенные как методы по умолчанию в интерфейсах, это будет бесполезно, поскольку метод класса Object всегда будет использоваться. Поэтому, чтобы избежать путаницы, мы не можем использовать методы по умолчанию, которые переопределяют методы класса Object.
  • Стандартные методы интерфейса Java также называются методами Defender или виртуальными расширениями.

Ссылка на ресурс:


Статический метод интерфейса Java

Статический метод интерфейса Java, пример кода, метод static method vs default

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

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Теперь давайте посмотрим класс реализации, имеющий метод isNull() с плохой реализацией.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

Обратите внимание: isNull (String str) - это простой метод класса, который не отменяет метод интерфейса. Например, если мы добавим аннотацию @Override к методу isNull(), это приведет к ошибке компилятора.

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

Интерфейс Null Check

Impl Null Check

Если мы сделаем метод интерфейса от статического по умолчанию, мы получим следующий вывод.

Impl Null Check

MyData Print::

Impl Null Check

Статический метод интерфейса Java виден только для методов интерфейса, если мы удалим метод isNull() из класса MyDataImpl, мы не сможем использовать его для объекта MyDataImpl. Однако, как и другие статические методы, мы можем использовать статические методы интерфейса, используя имя класса. Например, действительный оператор будет:

boolean result = MyData.isNull("abc");

Важные моменты о статическом методе Java-интерфейса:

  • Статический метод интерфейса Java является частью интерфейса, мы не можем использовать его для объектов класса реализации.
  • Статические методы интерфейса Java хороши для предоставления методов утилиты, например, проверка нулевого значения, сортировка коллекции и т.д.
  • Статический метод интерфейса Java помогает нам обеспечить безопасность, не позволяя классам реализации переопределять их.
  • Мы не можем определить статический метод интерфейса для методов класса Object, мы получим ошибку компилятора как "Этот статический метод не может скрыть метод экземпляра из объекта". Это связано с тем, что он не разрешен в java, поскольку Object является базовым классом для всех классов, и мы не можем иметь один статический метод уровня класса и другой метод экземпляра с одной и той же сигнатурой.
  • Мы можем использовать статические методы интерфейса Java для удаления классов утилиты, таких как коллекции, и переместить все свои статические методы в соответствующий интерфейс, который будет легко найти и использовать.

Функциональные интерфейсы Java

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

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

Функциональные интерфейсы долгожданы и востребованы функцией Java 8, потому что это позволяет нам использовать лямбда-выражения для их создания. Добавлен новый пакет java.util.function с набором функциональных интерфейсов для предоставления целевых типов для лямбда-выражений и ссылок на методы. Мы рассмотрим функциональные интерфейсы и лямбда-выражения в будущих сообщениях.

Местоположение ресурса:

Ответ 6

Все ваши утверждения действительны, кроме первого (после выпуска Java 8):

Методы интерфейса Java неявно абстрактны и не могут иметь реализации

Со страницы документации page:

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

Тела методов существуют только для стандартных методов и статических методов.

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

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

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

Расширяя интерфейс, содержащий метод по умолчанию, вы можете делать следующее:

  1. Ни в коем случае не упоминайте метод по умолчанию, который позволяет вашему расширенному интерфейсу наследовать метод по умолчанию.
  2. Переопределите метод по умолчанию, что делает его abstract.
  3. Переопределите метод по умолчанию, который переопределяет его.

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

В дополнение к методам по умолчанию вы можете определять статические методы в интерфейсах. (Статический метод - это метод, связанный с классом, в котором он определен, а не с каким-либо объектом. Каждый экземпляр класса совместно использует свои статические методы.)

Это упрощает организацию вспомогательных методов в ваших библиотеках;

Пример кода со страницы документации о том, что interface имеет методы static и default.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

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

Интерфейс:

  1. Чтобы определить контракт (желательно без сохранения состояния - я имею в виду без переменных)
  2. Чтобы связать несвязанные классы с , есть возможности.
  3. Объявление открытых константных переменных (неизменное состояние)

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

  1. Поделитесь кодом среди нескольких тесно связанных классов. Он устанавливает отношение.

  2. Совместное использование общего состояния между связанными классами (состояние можно изменить в конкретных классах)

Похожие посты:

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

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

Изучив эти примеры, вы поймете, что

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

Ответ 7

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

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

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

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

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

Ответ 8

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

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

Резюме

  • Интерфейс определяет контракт, который выполнит некоторая реализация.

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

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

Альтернативное резюме

  • Интерфейс предназначен для определения общедоступных API
  • Абстрактный класс предназначен для внутреннего использования и для определения SPI

В примере

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

С другой стороны, пользователям высокого уровня списка действительно не важно, как они реализованы, и они должны быть изолированы от этих деталей. Представьте себе, что Java не раскрывает интерфейс List, но имеет только конкретный класс List, который фактически является тем, что LinkedList сейчас. Все разработчики Java должны были настроить свой код для соответствия деталям реализации: избегать случайного доступа, добавлять кеш для ускорения доступа или просто переопределять ArrayList самостоятельно, хотя это было бы несовместимо со всем другим кодом, который действительно работает с List. Это было бы ужасно... Но теперь представьте себе, что мастера Java фактически понимают, что связанный список ужасен для большинства реальных случаев использования и решил перейти к списку массивов только для своего класса List. Это повлияет на производительность каждой Java-программы в мире, и люди не будут рады этому. И основным виновником является то, что детали реализации были доступны, и разработчики предположили, что эти детали являются постоянным контрактом, на который они могут положиться. Вот почему важно скрыть детали реализации и определить только абстрактный контракт. Это цель интерфейса: определить, какой тип ввода принимает метод, и какой вид вывода ожидается, не подвергая все кишки, которые заставляют программистов настраивать свой код, чтобы он соответствовал внутренним деталям, которые могут измениться при любом будущем обновлении.

Абстрактный класс находится в середине между интерфейсами и конкретными классами. Предполагается, что эта реализация поможет использовать общий или скучный код. Например, AbstractCollection предоставляет базовые реализации для isEmpty на основе размера 0, contains как повторение и сравнение, addAll как повторяющееся add и т.д. Это позволяет реализациям сосредоточиться на ключевых частях, которые различают их: как фактически хранить и извлекать данные.

Другая перспектива: API по сравнению с SPI

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

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

Разница между API и SPI является тонкой, но важной: для API основное внимание уделяется тем, кто использует, а для SPI основное внимание уделяется тому, кто реализует.

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

Заметка о Java 8 и методах по умолчанию

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

"Знание книг"

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

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

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

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

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

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

Ответ 9

Интерфейс - это "контракт", в котором класс, реализующий контракт promises, реализует методы. Примером, когда мне пришлось писать интерфейс вместо класса, было то, что я обновлял игру от 2D до 3D. Мне пришлось создать интерфейс для совместного использования классов между 2D и 3D-версией игры.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

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

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Как правило, в игровом мире мир может быть абстрактным классом, который выполняет методы в игре:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

Ответ 10

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

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

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

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

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

Ответ 11

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

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

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

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

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

Ответ 12

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

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

Ответ 13

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

Ответ 14

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

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

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

Ответ 15

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

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

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

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

Ответ 16

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

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

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

Ответ 18

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

Ответ 19

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

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

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

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

Ответ 20

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

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

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

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

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

Ответ 21

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

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

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

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

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

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

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

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

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

Ответ 22

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

Ответ 23

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

Ответ 24

Почти все, кажется, здесь уже рассмотрено. Добавляем еще один пример практической реализации класса abstract:

Ключевое слово

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

Ответ 25

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

после завершения вашего ответа вы должны перейти на пример:

Аннотация:

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

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

Интерфейс

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

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

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

}

class PermanentOne implements EmployeType
{

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

}

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

Ответ 26

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

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

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

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

Ответ 27

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

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

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

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

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

Удачи в следующем интервью!

Ответ 28

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

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

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

Теперь вы можете спросить, что, если Runnable был абстрактным классом?

Ну, технически это было возможно, но дизайн был мудрым, что было бы плохой причиной выбора:

  • Runnable не имеет состояния, связанного с ним, и ни один из них не предлагает никаких по умолчанию для метода run()
  • Задача должна была продлить ее, чтобы она не могла распространять любой другой класс
  • Задача не имеет ничего общего с классом Runnable, все, что ему нужно, это переопределить метод run()

Другими словами, класс Task нуждался в возможности запуска в потоке, который был достигнут путем реализации стилей интерфейса Runnable, расширяющих класс Thread, который сделал бы его потоком.

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

Отказ от ответственности: следует глупый пример, постарайтесь не судить:-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

Теперь у вас есть выбор быть GodLike, но вы можете выбрать только Forgiver (то есть не GodLike) и делать:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Или вы можете выбрать GodLike и делать:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

P.S. с интерфейсом java 8 также может иметь статические, а также методы по умолчанию (переопределяемые реализации), и, таким образом, интерфейс b/w с разницей и абстрактный класс еще более сужаются.

Ответ 29

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

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

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

Интерфейс

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

Ответ 30

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

Интерфейс - не интерфейс Java, а "интерфейс" в более общих терминах - к модулю кода - это, в основном, контракт с клиентским кодом, который использует интерфейс.

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

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

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