Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Abstract Class vs Interface: фундаментальные различия
Это один из самых важных вопросов в Java, потому что выбор между абстрактным классом и интерфейсом кардинально влияет на дизайн системы.
Быстрое сравнение
| Параметр | Abstract Class | Interface |
|---|---|---|
| Наследование | Один класс (IS-A) | Много интерфейсов (CAN-DO) |
| Конструктор | Может быть | Не может быть |
| Поля | Любые (final, static) | Только public static final |
| Методы | Любые (public, private, protected) | public (default с Java 9) |
| Состояние | Может иметь состояние | Не может (только константы) |
| Назначение | Определить "что это" | Определить "что оно может делать" |
Пример 1: IS-A vs CAN-DO (основное различие)
Abstract Class (IS-A отношение):
// "Это животное"
abstract class Animal {
private String name;
private int age; // СОСТОЯНИЕ
// Конструктор — инициализируем состояние
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// Абстрактный метод — каждое животное по-своему
abstract void makeSound();
// Конкретный метод — может быть у всех животных
public void sleep() {
System.out.println(name + " is sleeping");
}
// Protected методы — только для наследников
protected void grow() {
age++;
}
}
// Наследование: Dog ЭТО Animal
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age); // Инициализируем состояние родителя
}
@Override
void makeSound() {
System.out.println("Woof!");
}
}
Interface (CAN-DO отношение):
// "Это может летать"
interface Flyable {
void fly();
void land();
}
// "Это может плавать"
interface Swimmable {
void swim();
void dive();
}
// Класс может ДЕЛАТЬ много вещей
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
}
Пример 2: Состояние (State)
Abstract Class может иметь состояние:
abstract class Vehicle {
// Состояние — переменные экземпляра
private int speed;
private String color;
protected void accelerate(int amount) {
this.speed += amount; // Изменяем состояние
}
}
Interface НЕ может иметь состояние:
interface Drivable {
// Только константы
int MAX_SPEED = 200;
void drive();
}
Пример 3: Конструкторы
Abstract Class может иметь конструктор:
abstract class DatabaseConnection {
private String url;
// Конструктор
protected DatabaseConnection(String url) {
this.url = url;
}
}
Interface НЕ может иметь конструктор:
public interface Serializable {
// Конструктор запрещен!
}
Пример 4: Доступ (Access Modifiers)
Abstract Class — разные уровни доступа:
abstract class BankAccount {
private double balance; // private
protected void deposit(double amount) { } // protected
public void withdraw(double amount) { } // public
abstract double calculateInterest(); // abstract
}
Interface — все методы public:
public interface PaymentProcessor {
void processPayment(BigDecimal amount); // public
default void logTransaction(String id) { } // default с Java 9
}
Пример 5: Множественное наследование
Abstract Class — только один родитель:
// Ошибка!
// class Dog extends Animal, Mammal { }
// Правильно:
class Dog extends Animal { }
Interface — много интерфейсов:
// Правильно!
class Bird implements Flyable, Eatable, Observable {
@Override
public void fly() { }
@Override
public void eat() { }
@Override
public void observe() { }
}
Когда использовать что
Abstract Class когда:
// 1. IS-A отношение
abstract class PaymentMethod { }
// 2. Общая реализация
abstract class Repository<T> {
public List<T> findAll() { /* общая */ }
}
// 3. Состояние (не константы)
abstract class HttpRequest {
private String url;
private Map<String, String> headers;
}
// 4. Разные уровни доступа
abstract class Service {
private void internalValidation() { }
protected void preprocessData() { }
}
Interface когда:
// 1. CAN-DO отношение
interface Comparable<T> {
int compareTo(T o);
}
// 2. Контрактная гарантия
interface DataSource {
Connection getConnection();
void close();
}
// 3. Множественное наследование
class FileProcessor implements Runnable, Closeable, Comparable { }
Практический пример
// АБСТРАКТНЫЙ КЛАСС: базовая реализация
abstract class BaseRepository<T> {
protected JdbcTemplate jdbc;
public void save(T entity) { /* ... */ }
abstract String getTableName();
abstract T mapRow(ResultSet rs);
}
// ИНТЕРФЕЙСЫ: контракты
interface Cacheable { void clearCache(); }
interface Auditable { void logChange(String field, Object old, Object newVal); }
// КОНКРЕТНЫЙ КЛАСС
class UserRepository extends BaseRepository<User>
implements Cacheable, Auditable {
@Override
String getTableName() { return "users"; }
@Override
User mapRow(ResultSet rs) { return new User(/* ... */); }
@Override
public void clearCache() { /* ... */ }
@Override
public void logChange(String field, Object old, Object newVal) { /* ... */ }
}
Вывод
Abstract Class:
- IS-A отношение (Dog ЭТО Animal)
- Общая реализация и состояние
- Один родитель
- Разные уровни доступа
Interface:
- CAN-DO отношение (что может делать)
- Только контракт
- Множественное наследование
- Все методы public
Правильный выбор — основа хорошей архитектуры.