Generics lader dig skrive klasser, interfaces og metoder, der fungerer med en typeparameter specificeret af kalderen — hvilket giver compile-time typesikkerhed og eliminerer casts. De driver Collections Framework og genbrugbare biblioteker.
Problemet, som generics løser
// ❌ before generics (or with raw types) — no type safety, requires casts
List list = new ArrayList();
list.add("hello");
list.add(42); // oops — anything can go in
String s = (String) list.get(1); // ClassCastException at RUNTIME! 💥
// ✅ with generics — the type is enforced at COMPILE time
List<String> list = new ArrayList<>();
list.add("hello");
list.add(42); // ❌ compile error — caught immediately
String s = list.get(0); // no cast needed — known to be String
Generics flytter typefejl fra runtime (ClassCastException) til compile time, og fjerner behovet for manuelle casts — hvilket gør koden sikrere og renere.
Generiske klasser og metoder
// a generic class — T is a type parameter filled in by the user
public class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Box<String> b = new Box<>(); // T = String
b.set("hi");
String x = b.get(); // typed, no cast
// a generic method
public static <T> T firstElement(List<T> list) {
return list.get(0);
}
Begrænset typeparametre
// T must be Number (or a subclass) — lets you call Number methods
public static <T extends Number> double sum(List<T> list) {
double total = 0;
for (T n : list) total += n.doubleValue(); // safe — T is a Number
return total;
}
<T extends X> begrænser typeparametren, hvilket giver dig mulighed for sikkert at bruge den pågældende types medlemmer.
Wildcards
List<? extends Number> nums; // "some subtype of Number" — read (producer)
List<? super Integer> sink; // "Integer or a supertype" — write (consumer)
// PECS: Producer Extends, Consumer Super
Wildcards tilføjer fleksibilitet for metodeparametre, der skal acceptere rækker af typer.
Typesletning (en Java-advarsel)
// generics are a COMPILE-TIME feature — erased at runtime (for backward compatibility)
List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
a.getClass() == b.getClass(); // true — both are just ArrayList at runtime
// consequence: can't do `new T()` or `instanceof List<String>`
Java implementerer generics via typesletning — typeparametre findes ved compile time, men fjernes ved runtime, hvilket har nogle begrænsninger.
Hvorfor det betyder noget
Generics er vigtig for moderne Java — de giver compile-time typesikkerhed (der opdager typefejl tidligt i stedet for som runtime ClassCastExceptions), eliminerer verbost og fejlpronetcast, og muliggør genbrugelig, typefleksibel kode.
De er grundlaget for hele Collections Framework (List<String>, Map<K,V>) og utallige biblioteker.
At forstå generiske klasser/metoder, begrænsede parametre, wildcards (PECS) og typesletnings-forbeholdet lader dig både bruge generiske API'er korrekt og designe dine egne genbrugelige, typesikre abstraktioner — en kernefærdighed ved at skrive robust, vedligeholdelig Java.
