Каковы ключевые различия между интерфейсом и абстрактным классом в Java?

Ответ

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

Критерий Интерфейс (до Java 8+) Абстрактный класс
Состояние Только static final константы Может содержать любые поля (состояние объекта)
Конструкторы Не может иметь Может иметь конструкторы (для инициализации состояния)
Модификаторы методов Неявно publicabstract до Java 8) Любые (protected, private и т.д.)
Реализация по умолчанию default и static методы (с Java 8) Полностью реализованные методы
Наследование Класс может реализовать много интерфейсов Класс может наследовать только один абстрактный класс

Пример:

// Интерфейс определяет контракт
interface Loggable {
    String LOG_PREFIX = "LOG:"; // Константа
    void log(); // Абстрактный метод (неявно public)
    default void printTimestamp() { // Реализация по умолчанию
        System.out.println("Time: " + Instant.now());
    }
}

// Абстрактный класс может содержать состояние и общую логику
abstract class Shape {
    protected String color; // Поле с состоянием
    public Shape(String color) { this.color = color; } // Конструктор
    abstract double area(); // Абстрактный метод
    public String getColor() { return color; } // Реализованный метод
}

Когда что использовать:

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

Ответ 18+ 🔞

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

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

Интерфейс (старый, добрый, до восьмой джавы) — это как устный договор, блядь.
Чистый контракт, пиздец. "Ты, чувак, обязан уметь делать log(). Как ты это сделаешь — твои проблемы, но метод этот должен быть, и он должен быть публичным, а то я тебя в сраку!" Состояния? Нихуя! Только константы, static final, которые как гвозди в стену прибиты. Конструкторов? Вообще ни одного, блядь, рождаться ты должен как-то сам. Это просто список требований, не больше.

Абстрактный класс — это уже не договор, а почти готовый родитель, блядь.
У него уже может быть своя хитрая жопа — поля, состояние, цвет там какой-нибудь color. У него есть конструктор, чтобы это состояние при рождении задать. Методы он может прятать как хочет — private, protected, кому что надо. И главное — он уже может часть работы сделать за тебя, оставить только самое страшное (типа area()) на твою совесть.

А потом пришла Java 8, и в интерфейсах началась, блядь, настоящая движуха.
Короче, теперь в интерфейс можно пихать default методы — это типа "вот тебе готовая реализация на все случаи жизни, но если хочешь — перепиши, заёб". И static методы тоже. Так что теперь интерфейс — это не просто контракт, а ещё и набор готовых кирпичей, ёпта.

Пример, чтобы вообще мозг не взорвался:

// Интерфейс — контракт с фишками
interface Loggable {
    String LOG_PREFIX = "LOG:"; // Константа, прибита гвоздями
    void log(); // Делай, сука, но как хочешь
    default void printTimestamp() { // А это тебе подарок, на
        System.out.println("Time: " + Instant.now());
    }
}

// Абстрактный класс — почти готовый предок
abstract class Shape {
    protected String color; // А вот тут уже состояние, хитрая жопа!
    public Shape(String color) { this.color = color; } // Родился — получи цвет
    abstract double area(); // А вот это, дружок, посчитай сам
    public String getColor() { return color; } // А это я уже за тебя сделал
}

Итог, блядь, когда что брать:

  • Интерфейс — когда тебе нужно описать возможность. "Всё, что умеет логироваться", "Всё, что можно сортировать". Одна сущность может быть кучкой всего: и Loggable, и Serializable, и Comparable — интерфейсов можно навешать овердохуища.
  • Абстрактный класс — когда у тебя есть семейство объектов с общей, блядь, логикой и состоянием. Все Shape имеют цвет и как-то его возвращают, но площадь считают по-разному. И наследоваться можно только от одного такого предка, так что выбирай с умом, не распыляйся.

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