Interface: lényeg, szerződések Java és Kotlin környezetben Androidhoz

Szerző: IT Sectr Megjelenés: 2026-02-18 Olvasási idő: 9 perc

Interface — egy szerződés, amely meghatározza az absztrakt metódusok halmazát, amelyeket egy osztálynak meg kell valósítania. Java és Kotlin környezetben az interfészek az absztrakció és polimorfizmus fő mechanizmusai. Java 8+ környezetben az interfészek tartalmazhatnak default és static metódusokat, Kotlin környezetben — alapértelmezett megvalósításokat. A Google Android Developers (2025) szerint az interfészek az Android projektek 90%-ában használatosak az architektúra rétegeinek — repozitóriumok, UseCase-ek és szolgáltatások — meghatározására.

Főbb pontok

  • Interface — absztrakt típus, amely metódusok szignatúráit határozza meg megvalósítás nélkül (Java 8 előtt)
  • Implements — kulcsszó, amely összekapcsolja az osztályt az interfésszel; egy osztály több interfészt is megvalósíthat
  • Default method — megvalósítással rendelkező metódus a Java interfészben, Java 8-ban hozzáadva a visszafelé kompatibilitás érdekében
  • Kotlin interface támogatja a tulajdonságokat getterekkel és metódusmegvalósításokat, sok esetben helyettesítve az abstract class-t
  • Markup interface — üres interfész, címkeként használva (Serializable, Cloneable, RandomAccess)

Mi az Interface Java és Kotlin környezetben?

Interface — egy referenciatípus, amely absztrakt metódusokat, konstansokat és alapértelmezett metódusokat tartalmaz. Az interfészt megvalósító osztály köteles biztosítani annak összes absztrakt metódusának megvalósítását. Java környezetben az interfész nem rendelkezhet állapottal (példány mezőkkel), Kotlin is betartja ezt a korlátozást, de támogatja a tulajdonságokat hozzáférési függvényekkel.

Java
public interface Repository {
    T findById(Long id);
    List findAll();
    T save(T entity);
    void deleteById(Long id);
    
    default long count() {
        return findAll().size();
    }
}

@Entity
public class UserEntity {
    private Long id;
    private String email;
    // getterek és setterek
}

public class UserRepositoryImpl implements Repository {
    private final EntityManager em;
    
    public UserEntity findById(Long id) {
        return em.find(UserEntity.class, id);
    }
    
    public List findAll() {
        return em.createQuery("FROM UserEntity", UserEntity.class)
                .getResultList();
    }
    // többi metódus
}

Repository<T> — egy generikus interfész CRUD metódusokkal. Az count() alapértelmezett metódus egy felülírható alapértelmezett megvalósítást nyújt. A UserRepositoryImpl megvalósítja az interfészt, EntityManager-t használva az adatok eléréséhez. Ez a megközelítés lehetővé teszi az adatréteg tesztelését az interfész mock-ján keresztül valódi adatbázis nélkül.

Interface vs abstract class: mikor mit válasszunk

Az interfész és absztrakt osztály közötti választás a közös állapot meglététől és a típusok közötti kapcsolatoktól függ. Az interfész szerződést határoz meg (mit tehet az osztály), az absztrakt osztály — közös megvalósítást (mi az osztály).

KritériumInterfaceAbstract Class
Állapot (mezők)Csak static final konstansokIgen, bármilyen mezők
KonstruktorokNemIgen
Többszörös öröklésIgen (implements)Nem (extends egy)
Hozzáférési módosítókpublic (Java 8-), default metódusokMind (private, protected, public)
Mikor használdSzerződés nem rokon osztályok számáraKözös alap rokon osztályok számára

A Clean Architecture rendszerben az interfészek a belső rétegben (domain), a megvalósítások pedig a külső rétegben (data) helyezkednek el. Ez lehetővé teszi a Függőségi Szabály betartását: a külső réteg függ a belsőtől, nem fordítva. Az absztrakt osztályokat gyakrabban használják sablon metódusokhoz (Template Method pattern).

Interface Kotlin környezetben: tulajdonságok és delegáltak

A Kotlin interfészek rugalmasabbak, mint a Java-é: deklarálhatnak absztrakt tulajdonságokat és nyújthatnak metódusmegvalósításokat. A Java-tól eltérően a Kotlin támogatja a delegálást a by kulcsszó segítségével, ami jelentősen csökkenti a boilerplate kódot a Delegate minta megvalósításakor.

Kotlin
interface ApiService {
    val baseUrl: String  // absztrakt tulajdonság
    
    suspend fun fetchData(): Result>
    
    fun getEndpoint(path: String): String {
        return "$baseUrl/$path"  // alapértelmezett megvalósítás
    }
}

class RetrofitApiService(
    override val baseUrl: String
) : ApiService {
    private val client = Retrofit.Builder()
        .baseUrl(baseUrl)
        .build()
    
    override suspend fun fetchData(): Result> {
        // kérés megvalósítása
    }
}

// Delegálás by segítségével
interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) = println(message)
}

class UserService(logger: Logger) : Logger by logger

UserService megvalósítja a Logger interfészt delegálással (by). Az összes log() hívás a logger objektumhoz kerül átirányításra anélkül, hogy wrapper metódusokat kellene írni. Ez egy példa a kompozícióra, amely Java környezetben 5-10 sor boilerplate kódot igényelne.

Interface a Clean Architecture Android rendszerben

Clean Architecture Android rendszerben egyértelműen rétegekre bontja az alkalmazást. Az interfészek határként szolgálnak a rétegek között: a Domain meghatározza a repozitóriumok és UseCase-ek interfészeit, a Data biztosítja a megvalósításokat. Ez lehetővé teszi a megvalósítások cseréjét az üzleti logika módosítása nélkül — kulcsfontosságú előny a Room-ról Firebase-re vagy REST-ről GraphQL-re történő migráció során.

Kotlin
// Domain réteg — interfész (szerződés)
interface UserRepository {
    suspend fun getUser(id: String): User
    suspend fun updateUser(user: User)
}

// Domain réteg — use case (függ az interfésztől)
class GetUserUseCase(
    private val repository: UserRepository
) {
    suspend operator fun invoke(id: String): Result {
        return runCatching { repository.getUser(id) }
    }
}

// Data réteg — megvalósítás
class UserRepositoryImpl(
    private val api: UserApi,
    private val dao: UserDao
) : UserRepository {
    override suspend fun getUser(id: String): User {
        val cached = dao.getUser(id)
        if (cached != null) return cached
        val remote = api.fetchUser(id)
        dao.insertUser(remote)
        return remote
    }
    // updateUser...
}

UserRepository — interfész a domain rétegben. A GetUserUseCase az interfésztől függ, nem a megvalósítástól. A UserRepositoryImpl az adatrétegben megvalósítja az interfészt, kombinálva az API-t és a helyi adatbázist. Ez az architektúra lehetővé teszi a UseCase-ek tesztelését mock repozitóriummal adatbázis vagy hálózat konfigurációja nélkül.

Default és static metódusok Java 8+ környezetben

A default metódusok Java 8-ban kerültek hozzáadásra az interfészek evolúciós bővítéséhez a visszafelé kompatibilitás megsértése nélkül. Ha az ArrayList nem valósította volna meg a Collection-hez hozzáadott új stream() metódust, a régi kód tovább működött volna. A static metódusok az interfészekben az interfészhez kapcsolódó segédfunkciók számára szolgálnak — alternatíva a segédosztályokhoz.

Java
public interface Vehicle {
    void start();
    void stop();
    
    default void honk() {
        System.out.println("Beep!");
    }
    
    static Vehicle of(String type) {
        if ("car".equals(type)) return new Car();
        return new Bicycle();
    }
    
    // konstans
    String CATEGORY = "transport";
}

A default metódusok megoldják a gyémánt problémát (diamond problem): ha egy osztály két interfészt valósít meg ugyanazzal a default metódussal, a fordító explicit felülírást követel meg. A static metódusok az interfész nevével hívhatók — Vehicle.of("car"), példány nélkül.

Gyakori hibák az interfészek tervezése során

Az interfészek tervezésének hibái törékeny kódhoz, tesztelési nehézségekhez és SOLID megsértéséhez vezetnek. Vizsgáljunk meg három gyakori problémát.

Interface Pollution — túl sok metódus egy interfészben

Egy 15+ metódust tartalmazó interfész megsérti az Interface Segregation Principle (ISP) elvet. Példa — a régi java.util.Dictionary 10+ metódussal. Megoldás: osszuk fel több kisebb interfészre — ReadableRepository, WritableRepository, SearchableRepository. Az ügyfél (szolgáltatás) csak a számára szükséges metódusoktól függ.

Túlzott absztrakció — interfész minden osztályhoz

Interfész létrehozása minden osztályhoz valódi polimorfizmus igény nélkül az Interface overkill anti-minta. Jel: az interfésznek pontosan egy megvalósítása van, és a projektben nincsenek tervek alternatívák hozzáadására. Megoldás: csak akkor adj hozzá interfészt, amikor megjelenik a második megvalósítási változat, vagy szükség van mock-ra a tesztekhez.

Gyakran Ismételt Kérdések

Miben különbözik az interface az abstract class-tól Java környezetben?

Interface csak a szerződést (metódusok szignatúráit) határozza meg, nem rendelkezhet állapottal, és támogatja a többszörös öröklést. Abstract class tartalmazhat mezőket, konstruktorokat és megvalósított metódusokat, de egy osztály csak egy absztrakt osztályt örökölhet. Java 8-tól kezdve az interfészek default és static metódusokat kaptak, csökkentve a különbséget.

Örökölhet-e egy interfész egy másik interfészt?

Igen, Java és Kotlin környezetben az interfészek támogatják az öröklést. public interface AdvancedRepository<T> extends Repository<T>, Pageable — egy interfész, amely két másikat egyesít. Az AdvancedRepository-t megvalósító osztálynak meg kell valósítania mindkét szülő interfész összes metódusát. Többszörös öröklés csak interfészek számára engedélyezett.

Mi a funkcionális interfész Java környezetben?

Funkcionális interfész — egy absztrakt metódussal rendelkező interfész (SAM — Single Abstract Method). A @FunctionalInterface annotáció garantálja ezt a korlátozást. Példák: Runnable, Callable, Comparator, Consumer. A funkcionális interfészek képezik a Java 8 lambda kifejezéseinek alapját: () -> System.out.println() megvalósítja a Runnable-t.

Miért vannak szükség default metódusokra a Java interfészekben?

A default metódusok lehetővé teszik új metódusok hozzáadását egy interfészhez anélkül, hogy az összes megvalósító osztályt módosítani kellene. Például a Java 8 stream() metódusként adta hozzá a Collection-hez default metódusként. E mechanizmus nélkül a foreach(), stream() és más metódusok több ezer osztály módosítását igényelték volna a JDK-ban. A default — visszafelé kompatibilis bővítési mód.

Hogyan oldja meg a Kotlin a többszörös öröklés problémáját?

Kotlin megtiltja az osztályok többszörös öröklését, de engedélyezi az interfészek többszörös megvalósítását. Ha két interfész rendelkezik azonos szignatúrájú és alapértelmezett megvalósítású metódussal, a fordító explicit felülírást követel meg a super<InterfaceName>.method() hívással. Ez megoldja a gyémánt problémát fordítási szinten.

Összefoglalás

  • Interface — szerződés, amely meghatározza a megvalósítandó metódusokat; a polimorfizmus fő mechanizmusa Java és Kotlin környezetben
  • Java 8+ default és static metódusokat adott az interfészekhez, csökkentve a különbséget az absztrakt osztályokkal
  • Kotlin interfaces támogatják az absztrakt tulajdonságokat, alapértelmezett megvalósításokat és a by-val történő delegálást
  • Clean Architecture interfészeket használ határként a Domain és Data rétegek között
  • Interface Segregation Principle megköveteli a nagy interfészek szakosított interfészekre bontását
  • Funkcionális interfészek (Single Abstract Method) — a lambda kifejezések és Stream API alapja
  • Javaslat: adj hozzá interfészt, amikor megjelenik a második megvalósítás vagy szükség van mock-ra a teszteléshez

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is