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

1. Основные концептуальные различия

Характеристика Абстрактный класс Интерфейс
НазначениеЧастичная реализация + общий шаблонКонтракт для реализации
Ключевые словаabstract class в Kotlin/Javainterface в Kotlin/Java
ЭкземплярыНельзя создать напрямуюНельзя создать напрямую
НаследованиеОдиночное наследование (extends)Множественная реализация (implements)
Состояние (поля)Может содержать поля с состояниемТолько abstract свойства или константы
КонструкторыМожет иметь конструкторыНе может иметь конструкторов
Модификаторы доступаЛюбые (private, protected и т.д.)По умолчанию public

2. Детальное сравнение

2.1. Реализация методов

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

abstract class Animal {
    abstract fun makeSound()  // абстрактный метод (без реализации)

    fun eat() {              // метод с реализацией
        println("Eating...")
    }
}

Интерфейс (до Kotlin 1.4 / Java 8):

interface Drivable {
    fun drive()              // абстрактный метод

    // До Kotlin 1.4 нельзя было иметь реализацию
}

Современный интерфейс (Kotlin/Java 8+):

interface Drivable {
    fun drive()              // абстрактный метод

    fun startEngine() {      // метод с реализацией по умолчанию
        println("Engine started")
    }
}

2.2. Хранение состояния

Абстрактный класс может хранить состояние:

abstract class Vehicle(val maxSpeed: Double) {
    var currentSpeed: Double = 0.0
        protected set
}

Интерфейс не может хранить состояние (но в Kotlin может иметь свойства):

interface Clickable {
    val clickCount: Int     // абстрактное свойство

    // Не может иметь backing field (состояние)
}

2.3. Конструкторы

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

abstract class BaseActivity : AppCompatActivity() {
    constructor(layoutId: Int) : super() {
        setContentView(layoutId)
    }
}

Интерфейс не может иметь конструкторов!

3. Практические примеры в Android

Когда использовать абстрактный класс:

  1. BaseActivity:
abstract class BaseActivity : AppCompatActivity() {
    abstract val layoutId: Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layoutId)
        setupViews()
    }

    abstract fun setupViews()
}
  1. Частичная реализация RecyclerView.Adapter:
abstract class BaseAdapter<T> : RecyclerView.Adapter<BaseViewHolder<T>>() {
    protected val items = mutableListOf<T>()

    fun updateData(newItems: List<T>) {
        items.clear()
        items.addAll(newItems)
        notifyDataSetChanged()
    }

    override fun getItemCount() = items.size
}

Когда использовать интерфейс:

  1. Слушатели (Listeners):
interface OnItemClickListener {
    fun onItemClick(position: Int, view: View)
}
  1. Стратегии (Strategy pattern):
interface PaymentStrategy {
    fun pay(amount: Double)
}

class CreditCardPayment : PaymentStrategy { ... }
class PayPalPayment : PaymentStrategy { ... }

4. Эволюция интерфейсов

  1. Java 7 и ранее:

    • Только абстрактные методы
    • Только константы (public static final)
  2. Java 8+:

    • default методы
    • static методы в интерфейсах
  3. Kotlin:

    • Свойства в интерфейсах
    • Реализация методов по умолчанию
    • Функциональные интерфейсы (fun interface)

5. Правила выбора

Используйте абстрактный класс когда:

  • Нужно делиться общим кодом между несколькими классами
  • Требуется хранить состояние (поля класса)
  • Необходимы конструкторы или не-public методы
  • Логика тесно связана с наследованием

Используйте интерфейс когда:

  • Нужно определить контракт для разных реализаций
  • Требуется множественная "наследование" поведения
  • Хотите обеспечить слабую связанность компонентов
  • Работаете с лямбда-выражениями (функциональные интерфейсы)

Резюмируем

  1. Абстрактный класс - частичная реализация с возможностью хранения состояния и конструкторами.
  2. Интерфейс - чистый контракт (в основном), поддерживающий множественное наследование.
  3. Современные интерфейсы в Kotlin/Java 8+ стирают границы, но концептуальные различия остаются.
  4. В Android разработке:
    • Абстрактные классы часто используются для базовых Activity/Fragment/Adapters
    • Интерфейсы - для слушателей, стратегий и колбэков
  5. Выбор зависит от конкретной задачи и требований к архитектуре.

P.S. На собеседованиях часто просят привести примеры из реальной практики - будьте готовы рассказать, как вы использовали оба подхода в своих проектах!