Interface: суштина, уговори у Java и Kotlin за Android

Аутор: IT Sectr Објављено: 2026-02-18 Време читања: 9 мин

Interface — уговор који дефинише скуп апстрактних метода које класа мора да имплементира. У Java и Kotlin интерфејси су главни механизам апстракције и полиморфизма. У Java 8+ интерфејси могу садржати default и static методе, у Kotlin — имплементације подразумевано. Према Google Android Developers (2025), интерфејси се користе у 90% Android пројеката за дефинисање слојева архитектуре — репозиторијума, UseCase и сервиса.

Главно

  • Interface — апстрактни тип који дефинише сигнатуре метода без имплементације (пре Java 8)
  • Implements — кључна реч која повезује класу са интерфејсом; класа може имплементирати више интерфејса
  • Default method — метода са имплементацијом у Java интерфејсу, додата у Java 8 ради уназад компатибилности
  • Kotlin interface подржава својства са getter-има и имплементације метода, замењујући abstract class у многим сценаријима
  • Markup interface — празан интерфејс који се користи као ознака (Serializable, Cloneable, RandomAccess)

Шта је Interface у Java и Kotlin?

Interface — референтни тип који садржи апстрактне методе, константе и методе подразумевано. Класа која имплементира интерфејс мора да обезбеди имплементацију свих његових апстрактних метода. У Java интерфејс не може имати стање (поља инстанце), Kotlin се такође придржава овог ограничења, али подржава својства са акцесорима.

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;
    // getter-и и setter-и
}

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();
    }
    // остале методе
}

Repository<T> — generic интерфејс са CRUD методама. Default-метода count() пружа имплементацију подразумевано која се може прегазити. UserRepositoryImpl имплементира интерфејс, користећи EntityManager за приступ подацима. Овај приступ омогућава тестирање слоја података преко mock интерфејса без праве базе података.

Interface vs abstract class: када шта изабрати

Избор између интерфејса и апстрактне класе зависи од постојања заједничког стања и односа између типова. Интерфејс дефинише уговор (шта класа може да ради), апстрактна класа — заједничку имплементацију (шта класа јесте).

КритеријумInterfaceAbstract Class
Стање (поља)Само static final константеДа, било која поља
КонструкториНеДа
Вишеструко наслеђивањеДа (implements)Не (extends један)
Модификатори приступаpublic (Java 8-), default методеСви (private, protected, public)
Када користитиУговор за неповезане класеЗаједничка основа за сродне класе

У Clean Architecture интерфејси се налазе у унутрашњем слоју (domain), а имплементације — у спољашњем (data). Ово омогућава поштовање Правила зависности: спољашњи слој зависи од унутрашњег, али не обрнуто. Апстрактне класе се чешће користе за шаблонске методе (Template Method pattern).

Interface у Kotlin: својства и делегати

Kotlin интерфејси су флексибилнији од Java: могу декларисати апстрактна својства и пружати имплементације метода. За разлику од Java, Kotlin подржава делегирање кроз кључну реч by, што значајно смањује boilerplate при имплементацији Delegate шаблона.

Kotlin
interface ApiService {
    val baseUrl: String  // апстрактно својство
    
    suspend fun fetchData(): Result>
    
    fun getEndpoint(path: String): String {
        return "$baseUrl/$path"  // имплементација подразумевано
    }
}

class RetrofitApiService(
    override val baseUrl: String
) : ApiService {
    private val client = Retrofit.Builder()
        .baseUrl(baseUrl)
        .build()
    
    override suspend fun fetchData(): Result> {
        // имплементација захтева
    }
}

// Делегирање кроз by
interface Logger {
    fun log(message: String)
}

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

class UserService(logger: Logger) : Logger by logger

UserService имплементира интерфејс Logger кроз делегирање (by). Сви позиви log() се прослеђују објекту logger без писања wrapper метода. Ово је пример композиције која би у Java захтевала 5-10 линија boilerplate кода.

Interface у Clean Architecture Android

Clean Architecture за Android јасно раздваја апликацију на слојеве. Интерфејси играју улогу граница између слојева: Domain дефинише интерфејсе репозиторијума и UseCase-ова, Data пружа имплементације. Ово омогућава замену имплементација без промене пословне логике — кључна предност при миграцији са Room на Firebase или са REST на GraphQL.

Kotlin
// Domain слој — интерфејс (уговор)
interface UserRepository {
    suspend fun getUser(id: String): User
    suspend fun updateUser(user: User)
}

// Domain слој — use case (зависи од интерфејса)
class GetUserUseCase(
    private val repository: UserRepository
) {
    suspend operator fun invoke(id: String): Result {
        return runCatching { repository.getUser(id) }
    }
}

// Data слој — имплементација
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 — интерфејс у domain слоју. GetUserUseCase зависи од интерфејса, а не од имплементације. UserRepositoryImpl у data слоју имплементира интерфејс, комбинујући API и локалну базу података. Таква архитектура омогућава тестирање UseCase-ова са mock репозиторијумом без конфигурације базе података или мреже.

Default и static методе у Java 8+

Default методе су додате у Java 8 ради еволутивног проширења интерфејса без нарушавања уназад компатибилности. Да ArrayList није имплементирао нову методу stream() додату у Collection, стари код би наставио да ради. Static методе у интерфејсима служе за алате везане за интерфејс — алтернатива класама-алатима.

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();
    }
    
    // константа
    String CATEGORY = "transport";
}

Default-методе решавају дијамант проблем (diamond problem): ако класа имплементира два интерфејса са истом default-методом, компајлер захтева експлицитно прегажење. Static-методе се позивају преко имена интерфејса — Vehicle.of("car"), без инстанце.

Типичне грешке при пројектовању интерфејса

Грешке у пројектовању интерфејса доводе до крхког кода, тешкоћа у тестирању и кршења SOLID принципа. Размотримо три честа проблема.

Interface Pollution — превише метода у једном интерфејсу

Интерфејс са 15+ метода крши Interface Segregation Principle (ISP). Пример — стари java.util.Dictionary са 10+ метода. Решење: поделити на неколико малих интерфејса — ReadableRepository, WritableRepository, SearchableRepository. Клијент (сервис) зависи само од метода које су му потребне.

Претерана апстракција — интерфејс за сваку класу

Креирање интерфејса за сваку класу без стварне потребе за полиморфизмом је антишаблон Interface overkill. Знак: интерфејс има тачно једну имплементацију и у пројекту нема планова за додавање алтернатива. Решење: додавати интерфејс само када се појави друга верзија имплементације или потреба за mock-ом у тестовима.

Често постављана питања

По чему се interface разликује од abstract class у Java?

Interface дефинише само уговор (сигнатуре метода), не може имати стање и подржава вишеструко наслеђивање. Abstract class може садржати поља, конструкторе и имплементиране методе, али класа може наследити само једну апстрактну класу. Од Java 8 интерфејси су добили default и static методе, смањивши разлику.

Може ли интерфејс наследити други интерфејс?

Да, у Java и Kotlin интерфејси подржавају наслеђивање. public interface AdvancedRepository<T> extends Repository<T>, Pageable — интерфејс који обједињује два друга. Класа која имплементира AdvancedRepository мора имплементирати све методе оба родитељска интерфејса. Вишеструко наслеђивање је дозвољено само за интерфејсе.

Шта је функционални интерфејс у Java?

Функционални интерфејс — интерфејс са једном апстрактном методом (SAM — Single Abstract Method). Анотација @FunctionalInterface гарантује ово ограничење. Примери: Runnable, Callable, Comparator, Consumer. Функционални интерфејси су основа ламбда израза у Java 8: () -> System.out.println() имплементира Runnable.

Зашто су потребне default методе у Java интерфејсима?

Default методе омогућавају додавање нових метода у интерфејс без измене свих имплементирајућих класа. На пример, Java 8 је додала stream() у Collection као default-методу. Без овог механизма, foreach(), stream() и друге методе би захтевале промену хиљада класа у JDK. Default — уназад компатибилан начин проширења.

Како Kotlin решава проблем вишеструког наслеђивања?

Kotlin забрањује вишеструко наслеђивање класа, али дозвољава вишеструку имплементацију интерфејса. Ако два интерфејса имају методу са истом сигнатуром и имплементацијом подразумевано, компајлер захтева експлицитно прегажење са позивом super<InterfaceName>.method(). Ово решава дијамант проблем на нивоу компајлације.

Резиме

  • Interface — уговор који дефинише методе за имплементацију; главни механизам полиморфизма у Java и Kotlin
  • Java 8+ је додала default и static методе у интерфејсе, смањивши разлику са апстрактним класама
  • Kotlin interfaces подржавају апстрактна својства, имплементације подразумевано и делегирање кроз by
  • Clean Architecture користи интерфејсе као границе између Domain и Data слојева
  • Interface Segregation Principle захтева поделу великих интерфејса на специјализоване
  • Функционални интерфејси (Single Abstract Method) — основа ламбда израза и Stream API
  • Препорука: додајте интерфејс када се појави друга имплементација или потреба за mock-ом у тестирању

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође