Menu
Coddy logo textTech

Generics'e Giriş

Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 53 / 87.

Bir değer saklayan ve bu değeri daha sonra geri getiren bir sınıf oluşturmanız gerektiğini hayal edin. Generic'ler olmadan, her tür için ayrı sınıflar yazmanız gerekirdi; biri Integer için, biri String için, biri Double için vb. Bu durum kod tekrarına ve bakım zorluklarına yol açar.

Generic'ler, tip güvenliğini korurken herhangi bir tiple çalışan sınıflar ve metotlar yazmanıza olanak tanıyarak bu sorunu çözer. Sınıfı kullandığınızda gerçek bir tiple değiştirilen bir yer tutucu (tip parametresi olarak adlandırılır) tanımlarsınız:

// Generic'ler olmadan - Object kullanır, tür dönüştürme gerektirir
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Manuel tür dönüştürme gerekli

// Generic'ler ile - tip güvenli, tür dönüştürme yok
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // Tür dönüştürme gerekmez

Açılı ayraçlar <T> bir tip parametresini belirtir. List<String> yazdığınızda, derleyiciye bu listenin yalnızca dizeler içereceğini söylersiniz. Eğer bir tam sayı eklemeye çalışırsanız, derleyici hatayı çalışma zamanında başarısız olmak yerine hemen yakalar.

Generikler iki temel avantaj sağlar: açık tür dönüşümü (explicit casting) ihtiyacını ortadan kaldırırlar ve tür hatalarını çalışma zamanı yerine derleme zamanında yakalarlar. Bu, kodunuzu hem daha güvenli hem de daha temiz hale getirir. İlerleyen derslerde, kendi generic sınıflarınızı ve metotlarınızı nasıl oluşturacağınızı keşfedeceğiz.

challenge icon

Görev

Kolay

Eski yöntemi (tür dönüşümü ile Object kullanarak) yeni yöntemle (tür güvenliği ile generic kullanarak) karşılaştırarak generic yapısının gücünü gösteren basit bir depolama sistemi oluşturalım.

Aradaki farkı bizzat görmek için üç dosya oluşturacaksınız:

  • OldBox.java: Değerleri generic öncesi yöntemle saklayan bir sınıf oluşturun. OldBox sınıfınız Object türünde özel (private) bir content alanına sahip olmalıdır. Bir Object kabul eden ve onu saklayan bir yapıcı (constructor) ile Object döndüren bir getContent() metodu ekleyin. Bu yaklaşım çalışır ancak değerleri alırken tür dönüşümü (casting) gerektirir.
  • GenericBox.java: Şimdi generic kullanarak modern ve tür güvenli sürümü oluşturun. GenericBox sınıfınız, bildiriminde bir T tür parametresi kullanmalıdır. T türünde özel bir content alanına, bir T değeri kabul eden bir yapıcıya ve T türünü döndüren bir getContent() metoduna ihtiyaç duyar. Bu sınıfı kullanırken tür dönüşümüne gerek yoktur!
  • Main.java: Her iki yaklaşımı yan yana gösterin. İki girdi alacaksınız: bir kelime (String) ve bir sayı (integer).

    Önce eski yaklaşımı kullanın: kelimeyi saklayan bir OldBox oluşturun, ardından onu String türüne dönüştürerek geri alın ve şunu yazdırın: OldBox (with cast): [value]

    Ardından generic yaklaşımı kullanın: aynı kelimeyi saklayan bir GenericBox<String> oluşturun, tür dönüşümü yapmadan geri alın ve şunu yazdırın: GenericBox (no cast): [value]

    Sonra generic yapısının tam sayılarla çalışmasını gösterin: sayıyı saklayan bir GenericBox<Integer> oluşturun, onu geri alın ve şunu yazdırın: GenericBox Integer: [value]

    Son olarak, boş bir satır ve ardından şunu yazdırın: Type safety: Generics catch errors at compile time!

Sırasıyla iki girdi alacaksınız: bir kelime (String) ve bir sayı (String olarak gelen ve sizin ayrıştıracağınız integer).

Temel farka dikkat edin: OldBox ile (String) box.getContent() şeklinde tür dönüşümü yapmalı ve türü doğru tahmin ettiğinizi ummalısınız. GenericBox ile derleyici türü bilir ve tür dönüşümüne gerek kalmaz. Generic yapısının temel faydası budur—tür dönüşümü zahmeti olmadan tür güvenliği!

Kopya kağıdı

Generic yapılar, tip güvenliğini korurken herhangi bir tiple çalışan sınıflar ve metotlar yazmanıza olanak tanır. Sınıf kullanıldığında gerçek tiplerle değiştirilen tip parametrelerini (yer tutucuları) kullanırlar.

Generic yapılar olmadan (Object kullanarak):

List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Manuel tür dönüşümü (casting) gerekir

Generic yapılar ile (tip güvenli):

List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // Tür dönüşümüne gerek yok

Generic bir sınıf oluşturma:

public class GenericBox<T> {
    private T content;
    
    public GenericBox(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
}

Generic bir sınıfı kullanma:

GenericBox<String> stringBox = new GenericBox<String>("Hello");
String value = stringBox.getContent();  // Tür dönüşümü yok

GenericBox<Integer> intBox = new GenericBox<Integer>(42);
Integer number = intBox.getContent();  // Tip güvenli

Açılı ayraçlar <T> bir tip parametresini belirtir. Avantajları şunlardır: açıkça tür dönüşümü yapmaya gerek kalmaz ve tip hataları çalışma zamanı yerine derleme zamanında yakalanır.

Kendin dene

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: word saklayan bir OldBox oluşturun
        // String türüne dönüştürerek (cast) geri alın ve yazdırın: "OldBox (with cast): [value]"
        
        // TODO: word saklayan bir GenericBox<String> oluşturun
        // Tür dönüşümü (cast) yapmadan geri alın ve yazdırın: "GenericBox (no cast): [value]"
        
        // TODO: number saklayan bir GenericBox<Integer> oluşturun
        // Geri alın ve yazdırın: "GenericBox Integer: [value]"
        
        // TODO: Boş bir satır yazdırın, ardından şunu yazdırın:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler