- Soru: Java'da Generic nedir?
Cevap: Generic, Java'da tip güvenliği sağlayan ve çalışma zamanında oluşabilecek ClassCastException hatalarını önleyen bir özelliktir.
Açıklama: Generic'ler, farklı veri tipleriyle çalışabilen sınıflar, arayüzler ve metodlar yazmamızı sağlar.
Kod Örneği:
java
public class Box<T> { private T content; public void set(T content) { this.content = content; } public T get() { return content; } } // Kullanımı Box<String> stringBox = new Box<>(); stringBox.set("Hello World"); String content = stringBox.get(); // ClassCastException riski yok
- Soru: Generic'lerin avantajları nelerdir?
Cevap: Tip güvenliği, kod tekrarını azaltma, performans artışı ve daha okunabilir kod.
Kod Örneği:
java
// Generic olmadan List numbers = new ArrayList(); numbers.add(10); numbers.add("20"); // Hata yok, ama mantıksal olarak yanlış Integer num = (Integer) numbers.get(1); // Runtime'da ClassCastException // Generic ile List<Integer> numbers = new ArrayList<>(); numbers.add(10); // numbers.add("20"); // Derleme hatası, tip güvenliği sağlandı Integer num = numbers.get(1); // Cast işlemi gerekmiyor
- Soru: Java'da Generic tipleri nasıl tanımlanır?
Cevap: Generic tipler, sınıf veya arayüz adından sonra açılı parantez içinde belirtilir.
Kod Örneği:
java
public class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } // Kullanımı Pair<String, Integer> pair = new Pair<>("Age", 30);
- Soru: Generic metodlar nasıl tanımlanır?
Cevap: Generic metodlar, dönüş tipinden önce tip parametresi belirtilerek tanımlanır.
Kod Örneği:
java
public class Utilities { public static <T> void printArray(T[] array) { for (T element : array) { System.out.print(element + " "); } System.out.println(); } } // Kullanımı Integer[] intArray = {1, 2, 3, 4, 5}; String[] strArray = {"Hello", "World"}; Utilities.printArray(intArray); // 1 2 3 4 5 Utilities.printArray(strArray); // Hello World
- Soru: Bounded type parameter nedir?
Cevap: Bounded type parameter, generic tip parametresinin belirli bir üst sınıfa veya arayüze sahip olmasını zorunlu kılar.
Kod Örneği:
java
public class NumberBox<T extends Number> { private T number; public NumberBox(T number) { this.number = number; } public double sqrt() { return Math.sqrt(number.doubleValue()); } } // Kullanımı NumberBox<Integer> intBox = new NumberBox<>(16); System.out.println(intBox.sqrt()); // 4.0 // NumberBox<String> strBox = new NumberBox<>("16"); // Derleme hatası
- Soru: Wildcard nedir ve ne için kullanılır?
Cevap: Wildcard, bilinmeyen bir tipi temsil etmek için kullanılan
?
sembolüdür. Kod Örneği:javapublic static void printList(List<?> list) { for (Object elem : list) { System.out.print(elem + " "); } System.out.println(); } // Kullanımı List<Integer> intList = Arrays.asList(1, 2, 3); List<String> strList = Arrays.asList("Hello", "World"); printList(intList); // 1 2 3 printList(strList); // Hello World
- Soru: Upper bounded wildcard nedir?
Cevap: Upper bounded wildcard,
<? extends T>
şeklinde tanımlanır ve T veya T'nin alt sınıflarını kabul eder. Kod Örneği:javapublic static double sumOfList(List<? extends Number> list) { double sum = 0.0; for (Number num : list) { sum += num.doubleValue(); } return sum; } // Kullanımı List<Integer> intList = Arrays.asList(1, 2, 3); List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3); System.out.println(sumOfList(intList)); // 6.0 System.out.println(sumOfList(doubleList)); // 6.6
- Soru: Lower bounded wildcard nedir?
Cevap: Lower bounded wildcard,
<? super T>
şeklinde tanımlanır ve T veya T'nin üst sınıflarını kabul eder. Kod Örneği:javapublic static void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 5; i++) { list.add(i); } } // Kullanımı List<Number> numberList = new ArrayList<>(); addNumbers(numberList); System.out.println(numberList); // [1, 2, 3, 4, 5]
- Soru: Type erasure nedir?
Cevap: Type erasure, generic tiplerin derleme zamanında silinmesi ve runtime'da raw tiplere dönüştürülmesi işlemidir.
Kod Örneği:
java
// Derleme zamanında public class Box<T> { private T content; public void set(T content) { this.content = content; } public T get() { return content; } } // Runtime'da (type erasure sonrası) public class Box { private Object content; public void set(Object content) { this.content = content; } public Object get() { return content; } }
- Soru: Generic'lerde neden primitive tipler kullanılamaz?
Cevap: Java'da generic'ler yalnızca referans tipleriyle çalışır. Primitive tipler referans tipi olmadığı için doğrudan kullanılamazlar.
Kod Örneği:
java
// Geçersiz // List<int> intList = new ArrayList<>(); // Geçerli (wrapper sınıf kullanımı) List<Integer> intList = new ArrayList<>(); intList.add(1); // Autoboxing int first = intList.get(0); // Unboxing
javapublic class Container<T> { private T value; private static int count = 0; public Container(T value) { this.value = value; count++; } // Geçerli: static metod tip parametresi kullanmıyor public static int getCount() { return count; } // Geçersiz: static metod tip parametresi kullanamaz // public static T getValue() { return value; } } Container<String> c1 = new Container<>("Hello"); Container<Integer> c2 = new Container<>(42); System.out.println(Container.getCount()); // 2
java// Generic sınıf public class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } } // Generic metod public class Utilities { public static <T> T getFirst(List<T> list) { if (list.isEmpty()) { return null; } return list.get(0); } } // Kullanım Pair<String, Integer> pair = new Pair<>("Age", 30); List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); String firstName = Utilities.getFirst(names); // Tip çıkarımı yapılır
<>
), Java 7 ve sonrasında generic tiplerin oluşturulmasını kolaylaştıran bir sözdizimi özelliğidir.
Kod Örneği:
java// Java 7 öncesi Map<String, List<String>> map = new HashMap<String, List<String>>(); // Java 7 ve sonrası (diamond operator kullanımı) Map<String, List<String>> map = new HashMap<>();
java// Raw type kullanımı (önerilmez) List rawList = new ArrayList(); rawList.add("string"); rawList.add(42); // Generic kullanımı (önerilir) List<String> stringList = new ArrayList<>(); stringList.add("string"); // stringList.add(42); // Derleme hatası
javapublic class Pair<T, U> { private T first; private U second; public Pair(T first, U second) { this.first = first; this.second = second; } public static <T, U> Pair<T, U> of(T first, U second) { return new Pair<>(first, second); } } // Tip çıkarımı kullanımı Pair<String, Integer> pair = Pair.of("Age", 30); // Derleyici, Pair.of("Age", 30) ifadesinden T'nin String, U'nun Integer olduğunu çıkarır
java// T ve U burada type parameter public class Pair<T, U> { private T first; private U second; public Pair(T first, U second) { this.first = first; this.second = second; } } // String ve Integer burada type argument Pair<String, Integer> pair = new Pair<>("Hello", 42);
javapublic interface Comparable<T> { int compareTo(T o); } public class MyString implements Comparable<String> { public int compareTo(String o) { return 0; } } // Derleyici tarafından oluşturulan bridge method: // public bridge synthetic int compareTo(Object o) { // return this.compareTo((String) o); // }
javaList<String> stringList = new ArrayList<String>(); List rawList = stringList; rawList.add(42); // Heap pollution oluşur String s = stringList.get(0); // Runtime'da ClassCastException
new T()
kullanılamaz çünkü type erasure nedeniyle runtime'da T'nin gerçek tipi bilinmez.
Kod Örneği:
javapublic class Creator<T> { // Geçersiz // public T create() { // return new T(); // Derleme hatası // } // Geçerli alternatif public T create(Class<T> clazz) throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } Creator<String> stringCreator = new Creator<>(); String str = stringCreator.create(String.class);
java// Reifiable tipler List<String>[] arrayOfStringLists; // Geçerli List<?>[] arrayOfUnknownLists; // Geçerli // Non-reifiable tipler // List<String>[] arrayOfStringLists = new List<String>[10]; // Geçersiz // Yerine şu kullanılabilir: List<String>[] arrayOfStringLists = (List<String>[]) new List<?>[10];
public Type getType() { return type; } } TypeReference<List<String>> typeRef = new TypeReference<List<String>>() {}; Type listStringType = typeRef.getType(); System.out.println(listStringType); // java.util.List<java.lang.String>
Soru: Generic'lerde "type variable" nedir? Cevap: Type variable, generic sınıf, arayüz veya metot tanımında kullanılan sembolik bir tiptir. Kod Örneği: javapublic class Pair<T, U> { private T first; private U second; public Pair(T first, U second) { this.first = first; this.second = second; } } Pair<String, Integer> pair = new Pair<>("Hello", 42);
Soru: Generic'lerde "unbounded wildcard" nedir? Cevap: Unbounded wildcard, <?>
şeklinde gösterilen ve herhangi bir tipitemsil eden wildcard'dır. Kod Örneği: javapublic static void printList(List<?> list) { for (Object elem : list) { System.out.print(elem + " "); } System.out.println(); } List<Integer> intList = Arrays.asList(1, 2, 3); List<String> strList = Arrays.asList("A", "B", "C"); printList(intList); // 1 2 3 printList(strList); // A B C
Soru: Generic'lerde "recursive type bound" nedir? Cevap: Recursive type bound, bir tip parametresinin kendi tanımında kullanıldığı bir sınırlamadır. Kod Örneği: javapublic class Node<T extends Comparable<T>> implements Comparable<Node<T>> { private T data; private Node<T> next; public Node(T data) { this.data = data; } @Override public int compareTo(Node<T> other) { return this.data.compareTo(other.data); } } Node<String> node1 = new Node<>("A"); Node<String> node2 = new Node<>("B"); System.out.println(node1.compareTo(node2)); // -1
Soru: Generic'lerde "multiple bounds" nasıl kullanılır? Cevap: Multiple bounds, bir tip parametresinin birden fazla sınıf veya arayüzle sınırlandırılmasıdır. Kod Örneği: javainterface Drawable { void draw(); } interface Scalable { void scale(double factor); } public class Shape<T extends Drawable & Scalable> { private T item; public Shape(T item) { this.item = item; } public void drawAndScale() { item.draw(); item.scale(2.0); } } class Circle implements Drawable, Scalable { public void draw() { System.out.println("Drawing Circle"); } public void scale(double factor) { System.out.println("Scaling Circle by " + factor); } } Shape<Circle> circleShape = new Shape<>(new Circle()); circleShape.drawAndScale();
Soru: Generic'lerde "type inference" ne zaman başarısız olur? Cevap: Type inference, genellikle bağlam yeterli bilgi sağlamadığında başarısız olur. Kod Örneği: javapublic class Pair<T, U> { public static <T, U> Pair<T, U> create(T first, U second) { return new Pair<>(first, second); } } // Başarılı type inference Pair<String, Integer> pair1 = Pair.create("Hello", 42); // Başarısız type inference (açık tip belirtme gerekli) Pair<String, String> pair2 = Pair.<String, String>create(null, null);
Soru: Generic'lerde "raw type" kullanmanın riskleri nelerdir? Cevap: Raw type kullanmak tip güvenliğini ortadan kaldırır ve runtime hatalarına yol açabilir. Kod Örneği: javaList rawList = new ArrayList(); // raw type rawList.add("string"); rawList.add(42); for (Object obj : rawList) { String str = (String) obj; // 42 için ClassCastException System.out.println(str); } // Önerilen kullanım: List<String> safeList = new ArrayList<>(); safeList.add("string"); // safeList.add(42); // Derleme hatası
Soru: Generic'lerde "type erasure" neden uygulanmıştır? Cevap: Type erasure, geriye dönük uyumluluğu sağlamak için uygulanmıştır. Kod Örneği: java// Derleme zamanında public class Box<T> { private T value; public void set(T value) { this.value = value; } public T get() { return value; } } // Runtime'da (type erasure sonrası) public class Box { private Object value; public void set(Object value) { this.value = value; } public Object get() { return value; } }
Soru: Generic'lerde "wildcards" ile "type parameters" arasındaki fark nedir? Cevap: Wildcards ( ?
) bilinmeyen tipleri temsil ederken, type parameters( T
) belirli bir tipi temsil eder. Kod Örneği:java// Wildcard kullanımı public static void printList(List<?> list) { for (Object elem : list) { System.out.print(elem + " "); } } // Type parameter kullanımı public static <T> void printTypedList(List<T> list) { for (T elem : list) { System.out.print(elem + " "); } } List<Integer> intList = Arrays.asList(1, 2, 3); printList(intList); printTypedList(intList);
Soru: Generic'lerde "type parameter" için "default" değer belirlenebilir mi? Cevap: Hayır, Java'da generic tip parametreleri için default değer belirlenemez. Kod Örneği: java// Geçersiz: // public class DefaultBox<T = String> { ... } // Alternatif çözüm: public class Box<T> { private T value; public Box() { this(null); // Default constructor } public Box(T value) { this.value = value; } } Box<String> stringBox = new Box<>(); // Default olarak null Box<Integer> intBox = new Box<>(0); // Açıkça 0 ile başlatma
Soru: Generic'lerde "bounded type parameters" neden kullanılır? Cevap: Bounded type parameters, tip parametresinin özelliklerini sınırlandırarak daha spesifik işlemler yapılmasına olanak tanır. Kod Örneği: javapublic class NumberContainer<T extends Number> { private T number; public NumberContainer(T number) { this.number = number; } public double getSquareRoot() { return Math.sqrt(number.doubleValue()); } } NumberContainer<Integer> intContainer = new NumberContainer<>(16); System.out.println(intContainer.getSquareRoot()); // 4.0 // NumberContainer<String> strContainer = new NumberContainer<>("16"); // Derleme hatası
Soru: Generic'lerde "type parameter" isimlendirme konvansiyonları nelerdir? Cevap: Genellikle tek büyük harf kullanılır: E (Element), T (Type), K (Key), V (Value), N (Number). Kod Örneği: javapublic class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } Pair<String, Integer> pair = new Pair<>("Age", 30);
Soru: Generic'lerde neden dizi oluşturulamaz? (new T[]) Cevap: Type erasure nedeniyle, runtime'da T'nin gerçek tipi bilinmediği için generic tip array'leri doğrudan oluşturulamaz. Kod Örneği: javapublic class GenericArray<T> { // Geçersiz: // private T[] array = new T[10]; // Geçerli alternatif: private Object[] array; @SuppressWarnings("unchecked") public GenericArray(int size) { array = new Object[size]; } public void set(int index, T item) { array[index] = item; } @SuppressWarnings("unchecked") public T get(int index) { return (T) array[index]; } } GenericArray<String> stringArray = new GenericArray<>(5); stringArray.set(0, "Hello"); String str = stringArray.get(0);
Soru: Generic'lerde "type safety" nasıl sağlanır? Cevap: Generic'ler, derleme zamanında tip kontrolü yaparak type safety sağlar. Kod Örneği: javapublic class SafeBox<T> { private T content; public void set(T content) { this.content = content; } public T get() { return content; } } SafeBox<String> stringBox = new SafeBox<>(); stringBox.set("Hello"); // stringBox.set(42); // Derleme hatası String content = stringBox.get(); // Cast gerekmiyor
Soru: Generic'lerde "wildcards" ile "raw types" arasındaki fark nedir? Cevap: Wildcards tip güvenliği sağlarken, raw types tip güvenliğini ortadan kaldırır. Kod Örneği: java// Raw type (tip güvenliği yok) List rawList = new ArrayList(); rawList.add("string"); rawList.add(42); // Wildcard (tip güvenliği var) List<?> wildcardList = new ArrayList<String>(); // wildcardList.add("string"); // Derleme hatası // wildcardList.add(42); // Derleme hatası Object obj = wildcardList.get(0); // Güvenli
Soru: Generic'lerde "type witness" ne zaman gereklidir? Cevap: Type witness, derleyicinin tip çıkarımı yapamadığı durumlarda gereklidir. Kod Örneği: javaclass Utilities { public static <T> List<T> emptyList() { return new ArrayList<>(); } } // Type witness gerekli List<String> list1 = Utilities.<String>emptyList(); // Type witness gerekli değil (tip çıkarımı yapılabilir) List<Integer> list2 = Utilities.emptyList(); list2.add(42);
- Soru: Generic'lerde "invariance" neden varsayılan davranıştır? Cevap: Invariance, tip güvenliğini korumak için varsayılan davranıştır. Kod Örneği:
javaList<Number> numbers = new ArrayList<Number>(); numbers.add(1); numbers.add(1.0); // Aşağıdaki kod derlenmez: // List<Number> moreNumbers = new ArrayList<Integer>(); // Çünkü bu, List<Integer>'a bir Double eklenmesine izin verebilirdi. // Bunun yerine wildcard kullanılabilir: List<? extends Number> safeNumbers = new ArrayList<Integer>(); // safeNumbers.add(1); // Bu da derlenmez, çünkü hangi alt türün olduğunu bilmiyoruz Number n = safeNumbers.get(0); // Ama bu güvenlidir
- Soru: Generic'lerde "type erasure" sonrası method overloading nasıl çalışır? Cevap: Type erasure sonrası, generic parametreler silindiği için
- bazı method overloading durumları çakışabilir. Kod Örneği:
javapublic class OverloadExample { // Bu iki metod, type erasure sonrası aynı imzaya sahip olur public void print(List<String> list) { System.out.println("String list: " + list); } /* Bu metod derleme hatası verir public void print(List<Integer> list) { System.out.println("Integer list: " + list); } */ // Bunun yerine farklı metod isimleri kullanılabilir public void printStringList(List<String> list) { System.out.println("String list: " + list); } public void printIntegerList(List<Integer> list) { System.out.println("Integer list: " + list); } }
- Soru: Generic'lerde "type inference" ve "diamond operator" arasındaki
- ilişki nedir? Cevap: Diamond operator (
<>
), type inference'ı kolaylaştırmak için- Java 7'de tanıtılmıştır. Kod Örneği:
java// Java 7 öncesi Map<String, List<String>> map1 = new HashMap<String, List<String>>(); // Java 7 ve sonrası (diamond operator kullanımı) Map<String, List<String>> map2 = new HashMap<>(); // Tip çıkarımı yapılır // Java 10 ve sonrası (var keyword'ü ile) var map3 = new HashMap<String, List<String>>(); // Daha da gelişmiş tip çıkarımı
- Soru: Generic'lerde "bounded wildcard" ve "bounded type parameter" arasındaki
- fark nedir? Cevap: Bounded wildcard (
? extends
veya? super
) metot parametrelerinde- kullanılırken, bounded type parameter (
T extends
veyaT super
)- sınıf veya metot tanımlarında kullanılır. Kod Örneği:
java// Bounded wildcard public static double sumOfList(List<? extends Number> list) { double sum = 0.0; for (Number num : list) { sum += num.doubleValue(); } return sum; } // Bounded type parameter public static <T extends Number> double sumOfArray(T[] array) { double sum = 0.0; for (T num : array) { sum += num.doubleValue(); } return sum; } List<Integer> intList = Arrays.asList(1, 2, 3); Integer[] intArray = {1, 2, 3}; System.out.println(sumOfList(intList)); // 6.0 System.out.println(sumOfArray(intArray)); // 6.0
- Soru: Generic'lerde "type erasure" sonrası bridge method neden gereklidir? Cevap: Bridge method, type erasure sonrası oluşabilecek metot imza
- çakışmalarını çözmek için gereklidir. Kod Örneği:
javainterface Comparable<T> { int compareTo(T o); } class MyString implements Comparable<String> { public int compareTo(String o) { return 0; } } // Derleyici tarafından oluşturulan bridge method: // public int compareTo(Object o) { // return compareTo((String) o); // }
- Soru: Generic'lerde "type parameter" ve "wildcard" ne zaman tercih edilmelidir? Cevap: Type parameter genellikle sınıf veya metot tanımlarında,
- wildcard ise metot parametrelerinde tercih edilir. Kod Örneği:
java// Type parameter kullanımı public static <T> void swapElements(List<T> list, int i, int j) { T temp = list.get(i); list.set(i, list.get(j)); list.set(j, temp); } // Wildcard kullanımı public static void printList(List<?> list) { for (Object elem : list) { System.out.print(elem + " "); } System.out.println(); } List<String> strList = Arrays.asList("A", "B", "C"); swapElements(strList, 0, 2); printList(strList); // C B A
- Soru: Generic'lerde "type erasure" sonrası runtime'da tip bilgisine nasıl
- erişilir? Cevap: Reflection API kullanılarak veya tip token'ları ile erişilebilir. Kod Örneği:
javaimport java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; public class TypeInfo<T> { public Class<?> getTypeClass() { Type type = getClass().getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) type; return (Class<?>) paramType.getActualTypeArguments()[0]; } } TypeInfo<List<String>> typeInfo = new TypeInfo<List<String>>() {}; System.out.println(typeInfo.getTypeClass()); // class java.util.List
- Soru: Generic'lerde "heap pollution" nasıl önlenir? Cevap: Heap pollution genellikle raw tiplerin kullanımından kaynaklanır,
- bu nedenle raw tip kullanımından kaçınmak ve @SafeVarargs anotasyonunu
- dikkatli kullanmak önemlidir. Kod Örneği:
java@SafeVarargs public static <T> List<T> asList(T... elements) { return Arrays.asList(elements); } List<String> list = asList("A", "B", "C"); // Aşağıdaki kod derleme hatası verir ve heap pollution'ı önler // List<String> dangerousList = asList("A", "B", "C", 1);
- Soru: Generic'lerde "type inference" başarısız olduğunda ne yapılmalıdır? Cevap: Tip açıkça belirtilmelidir veya bağlam sağlanmalıdır. Kod Örneği:
javaclass Pair<T, U> { T first; U second; Pair(T first, U second) { this.first = first; this.second = second; } static <T, U> Pair<T, U> of(T first, U second) { return new Pair<>(first, second); } } // Tip çıkarımı başarısız olur // Pair<String, Integer> pair = Pair.of(null, null); // Çözüm 1: Tipleri açıkça belirtme Pair<String, Integer> pair1 = Pair.<String, Integer>of(null, null); // Çözüm 2: Bağlam sağlama Pair<String, Integer> pair2 = Pair.of("Hello", 42);
- Soru: Generic'lerde "capture conversion" nedir? Cevap: Capture conversion, wildcard tiplerini işlemek için derleyici
- tarafından kullanılan bir mekanizmadır. Kod Örneği:
javapublic static void reverse(List<?> list) { rev(list); } private static <T> void rev(List<T> list) { List<T> tmp = new ArrayList<>(list); for (int i = 0; i < list.size(); i++) { list.set(i, tmp.get(list.size() - i - 1)); } } List<String> strList = Arrays.asList("A", "B", "C"); reverse(strList); System.out.println(strList); // [C, B, A]