← Kursa Dön
📄 Text · 12 min

Interface Temelleri

Interface Nedir?

Interface, bir sınıfın ne yapması gerektiğini tanımlayan ama nasıl yapacağını söylemeyen bir sözleşmedir. Metot imzalarını belirler, implementasyonu sınıfa bırakır.

Bunu bir iş sözleşmesi gibi düşün. Sözleşme "web sitesi yapacaksın, mobil uygulama yapacaksın" diyor — ama hangi programlama dilini kullanacağın, kaç kişiyle çalışacağın sana kalmış. Interface de bu: "şu metotları sağlamalısın" der, gerisine karışmaz.

Interface Sözdizimi

interface Drawable {
    void draw();           // abstract metot (implicit)
    double getArea();      // abstract metot (implicit)
}

Interface'teki metotlar varsayılan olarak public abstract'tır — yazmasanız da öyle kabul edilir.

// Bu ikisi aynı anlama gelir:
void draw();
public abstract void draw();

implements Keyword'ü

Bir sınıf interface'i implements keyword'ü ile uygular. Interface'teki tüm abstract metotları implement etmek zorundadır.

interface Playable {
    void play();
    void stop();
}

class MusicPlayer implements Playable {
    @Override
    public void play() {
        System.out.println("Playing music...");
    }

    @Override
    public void stop() {
        System.out.println("Music stopped.");
    }
}

class VideoPlayer implements Playable {
    @Override
    public void play() {
        System.out.println("Playing video...");
    }

    @Override
    public void stop() {
        System.out.println("Video stopped.");
    }
}
Playable player = new MusicPlayer(); // Interface referansı
player.play(); // "Playing music..."
player.stop(); // "Music stopped."

player = new VideoPlayer(); // Aynı referans, farklı nesne
player.play(); // "Playing video..."

Polimorfizm burada da çalışıyor. Playable referansı herhangi bir implementasyonu tutabiliyor.

Çoklu Interface

Java'da bir sınıf sadece bir sınıftan extend edebilir ama birden fazla interface'i implement edebilir. Bu, Java'nın çoklu kalıtım eksikliğini telafi etme yolu.

interface Printable {
    void print();
}

interface Saveable {
    void save();
}

interface Exportable {
    void export(String format);
}

class Document implements Printable, Saveable, Exportable {
    String content;

    Document(String content) {
        this.content = content;
    }

    @Override
    public void print() {
        System.out.println("Printing: " + content);
    }

    @Override
    public void save() {
        System.out.println("Saving document...");
    }

    @Override
    public void export(String format) {
        System.out.println("Exporting as " + format);
    }
}
Document doc = new Document("Hello World");

Printable p = doc;  // Printable olarak kullan
p.print();

Saveable s = doc;   // Saveable olarak kullan
s.save();

Exportable e = doc; // Exportable olarak kullan
e.export("PDF");

Aynı nesne farklı interface referansları ile farklı "roller" üstlenebilir. Bu çok güçlü bir tasarım aracı.

Interface ve Kalıtım Birlikte

Bir sınıf hem bir sınıfı extend edip hem de interface'leri implement edebilir.

abstract class Vehicle {
    String brand;

    Vehicle(String brand) {
        this.brand = brand;
    }

    abstract void startEngine();
}

interface Electric {
    void charge();
    int getBatteryLevel();
}

interface Autonomous {
    void selfDrive();
}

class Tesla extends Vehicle implements Electric, Autonomous {
    int batteryLevel = 100;

    Tesla() {
        super("Tesla");
    }

    @Override
    void startEngine() {
        System.out.println("Electric motor humming...");
    }

    @Override
    public void charge() {
        batteryLevel = 100;
        System.out.println("Charging complete");
    }

    @Override
    public int getBatteryLevel() {
        return batteryLevel;
    }

    @Override
    public void selfDrive() {
        System.out.println("Autopilot engaged");
    }
}

Tesla hem bir Vehicle (IS-A), hem Electric, hem de Autonomous. Kalıtım ve interface birlikte kullanıldığında çok esnek tasarımlar oluşur.

Interface Alanları

Interface'te alan tanımlayabilirsin ama bunlar otomatik olarak public static final'dır — yani sabit (constant).

interface GameConstants {
    int MAX_PLAYERS = 4;      // public static final
    int MIN_PLAYERS = 1;      // public static final
    String VERSION = "1.0";   // public static final
}

class Game implements GameConstants {
    void start() {
        System.out.println("Version: " + VERSION);
        System.out.println("Max players: " + MAX_PLAYERS);
    }
}

Interface'te değişken tutamazsın — sadece sabit. Bu mantıklı çünkü interface "davranış sözleşmesi", durum (state) tutmak sınıfın işi.

💡 İpucu: Sabitler için interface kullanmak eski bir Java idiom'u. Modern Java'da enum veya final class ile sabit tanımlamak daha tercih edilen yaklaşım.

Interface vs Abstract Class

Bu ikisini ne zaman kullanacağını bilmek çok önemli.

ÖzellikInterfaceAbstract Class
Metotlarabstract + default + staticabstract + concrete
AlanlarSadece sabitler (static final)Her türlü alan
Constructor❌ Yok✅ Var
Çoklu implementasyon✅ (birden fazla)❌ (tek kalıtım)
Erişim belirteçleripublic (Java 9'da private de)Her türlü
Ne zaman?"Ne yapabilir?" sorusu"Ne tür bir şey?" sorusu

Interface kullan:

  • Birbiriyle alakasız sınıflar ortak davranış paylaşacaksa

  • Çoklu "yetenek" tanımlamak istiyorsan

  • API sözleşmesi tanımlıyorsan

Abstract class kullan:

  • Ortak kod paylaşmak istiyorsan (concrete metotlar)

  • Ortak durum (state/field) gerekiyorsa

  • "IS-A" ilişkisi olan sınıflar arasında

// Interface — yetenek tanımlama
interface Flyable {
    void fly();
}

// Farklı türdeki sınıflar aynı yeteneğe sahip
class Bird implements Flyable {
    @Override
    public void fly() { System.out.println("Flapping wings"); }
}

class Airplane implements Flyable {
    @Override
    public void fly() { System.out.println("Jet engines"); }
}

class Superman implements Flyable {
    @Override
    public void fly() { System.out.println("Up, up and away!"); }
}

Bird, Airplane ve Superman hiçbir ortak sınıftan türemiyor. Ama hepsi uçabiliyor. Interface bu tür "çapraz yetenekleri" modellemek için mükemmel.

Interface Kalıtımı

Interface'ler de birbirinden kalıtım alabilir — extends ile.

interface Readable {
    String read();
}

interface Writable {
    void write(String data);
}

interface ReadWritable extends Readable, Writable {
    // Readable ve Writable'ın tüm metotlarını miras alır
    void flush();
}

class File implements ReadWritable {
    @Override
    public String read() { return "file content"; }

    @Override
    public void write(String data) { System.out.println("Writing: " + data); }

    @Override
    public void flush() { System.out.println("Flushing buffer"); }
}

Dikkat: interface'ler arası kalıtımda extends kullanılır ve çoklu extends mümkündür. ReadWritable hem Readable hem Writable'ı extend ediyor.

Marker Interface

Hiçbir metodu olmayan interface'lere marker interface denir. Sınıfı "işaretler" — bir özelliğe sahip olduğunu belirtir.

// Java standart kütüphanesinden örnekler:
// java.io.Serializable — serileştirilebilir
// java.lang.Cloneable — kopyalanabilir

interface Deletable {
    // Hiç metot yok — sadece işaretleme
}

class TemporaryFile implements Deletable {
    String name;

    TemporaryFile(String name) {
        this.name = name;
    }
}

class PermanentFile {
    String name;

    PermanentFile(String name) {
        this.name = name;
    }
}
void cleanup(Object file) {
    if (file instanceof Deletable) {
        System.out.println("Deleting: " + file);
    } else {
        System.out.println("Skipping: " + file);
    }
}

Marker interface ile instanceof kontrolü yapabilirsin. Ama modern Java'da marker interface yerine annotation kullanımı daha yaygın.

⚠️ Dikkat: Marker interface kullanımı azalıyor. @Serializable, @Cacheable gibi annotation'lar aynı işi daha esnek şekilde yapar. Ama Serializable gibi eski API'larda hala marker interface görürsün.

Polimorfizm ve Interface

Interface referansları polimorfizm için mükemmeldir.

interface Sortable {
    int compareTo(Sortable other);
}

class Student implements Sortable {
    String name;
    double gpa;

    Student(String name, double gpa) {
        this.name = name;
        this.gpa = gpa;
    }

    @Override
    public int compareTo(Sortable other) {
        Student otherStudent = (Student) other;
        return Double.compare(this.gpa, otherStudent.gpa);
    }

    @Override
    public String toString() {
        return name + " (" + gpa + ")";
    }
}
List<Sortable> items = new ArrayList<>();
items.add(new Student("Ali", 3.5));
items.add(new Student("Ayşe", 3.8));
items.add(new Student("Mehmet", 3.2));
// Sıralama, filtreleme gibi işlemler Sortable referansıyla yapılabilir

Gerçekçi Örnek: Plugin Sistemi

Interface'lerin en güzel kullanımlarından biri plugin mimarileri.

interface Plugin {
    String getName();
    void initialize();
    void execute();
    void shutdown();
}

class LoggingPlugin implements Plugin {
    @Override
    public String getName() { return "Logging"; }

    @Override
    public void initialize() {
        System.out.println("Logger initialized");
    }

    @Override
    public void execute() {
        System.out.println("Logging events...");
    }

    @Override
    public void shutdown() {
        System.out.println("Logger shut down");
    }
}

class CachePlugin implements Plugin {
    @Override
    public String getName() { return "Cache"; }

    @Override
    public void initialize() {
        System.out.println("Cache warmed up");
    }

    @Override
    public void execute() {
        System.out.println("Serving from cache...");
    }

    @Override
    public void shutdown() {
        System.out.println("Cache flushed");
    }
}
class Application {
    List<Plugin> plugins = new ArrayList<>();

    void registerPlugin(Plugin plugin) {
        plugins.add(plugin);
    }

    void start() {
        for (Plugin p : plugins) {
            System.out.println("Starting: " + p.getName());
            p.initialize();
        }
    }

    void run() {
        for (Plugin p : plugins) {
            p.execute();
        }
    }

    void stop() {
        for (Plugin p : plugins) {
            p.shutdown();
        }
    }
}
Application app = new Application();
app.registerPlugin(new LoggingPlugin());
app.registerPlugin(new CachePlugin());
app.start();
app.run();
app.stop();

Application hiçbir plugin'in iç detayını bilmiyor. Sadece Plugin interface'ini biliyor. Yeni plugin eklemek için Application koduna dokunmak gerekmiyor.

Java Standart Kütüphanesindeki Interface'ler

Java'nın temel interface'lerinden bazıları:

InterfacePaketKullanım
Comparable<T>java.langDoğal sıralama
Iterable<T>java.langfor-each döngüsü
Serializablejava.ioSerileştirme
Cloneablejava.langNesne kopyalama
Runnablejava.langThread çalıştırma
List<T>java.utilListe davranışı
Map<K,V>java.utilAnahtar-değer
AutoCloseablejava.langtry-with-resources

Bu interface'leri ilerideki konularda sıklıkla kullanacağız.

⚠️ Dikkat: Interface isimlendirmesinde iki yaygın konvansiyon var: (1) sıfat gibi: Comparable, Serializable, Runnable (2) isim gibi: List, Map, Set. Java standart kütüphanesi ikisini de kullanır.


Özet

  • Interface, interface keyword'ü ile tanımlanır ve bir sınıfın sağlaması gereken metotların sözleşmesidir.

  • Sınıflar implements ile interface uygular; birden fazla interface implement edilebilir (çoklu kalıtımın alternatifi).

  • Interface'teki metotlar varsayılan olarak public abstract, alanlar public static final'dır.

  • Interface vs abstract class: Interface yetenek tanımlar ("ne yapabilir?"), abstract class tür tanımlar ("ne tür?"); ortak kod gerekiyorsa abstract class, çoklu yetenek gerekiyorsa interface kullan.

  • Marker interface (boş interface) bir sınıfı işaretler; modern Java'da annotation'lar bu rolü üstleniyor.

  • Interface'ler gevşek bağlı, genişletilebilir ve test edilebilir tasarımların temel yapı taşıdır.