Soru: Generic'lerde "reifiable type" nedir?
Cevap: Reifiable type, tüm tip bilgisi runtime'da mevcut olan tiptir.
Kod Örneği:
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:
java
public 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 tipi temsil eden wildcard'dır.
Kod Örneği:
java
public 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:
java
public 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:
java
interface 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:
java
public 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:
java
List 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:
java
public 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:
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; }
}
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:
java
public 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:
java
public 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:
java
class 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:
java
List<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:
java
public 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 veya T 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:
java
interface 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:
java
import 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:
java
class 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:
java
public 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]