Last 30 Days
No notifications
Generics let a class or method work with *any* type while keeping compile-time type safety. List means "a list of strings" — the compiler refuses anything else, and you don't need to cast on the way out. Underneath, Java implements generics with type erasure — generic info is stripped at runtime — which leads to a few quirks worth knowing.
# Generics
List names = new ArrayList();
names.add("alice");
names.add(42); // oops — no error
String s = (String) names.get(1); // ClassCastException at runtime
With them the compiler catches it:
List<String> names = new ArrayList<>();
names.add("alice");
names.add(42); // compile error
String s = names.get(0); // no cast neededpublic class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}Box<Integer> b = new Box<>();
b.set(42);
int x = b.get(); // auto-unboxed
public static <T> T firstOrNull(List<T> list) {
return list.isEmpty() ? null : list.get(0);
}String s = firstOrNull(List.of("a", "b")); // T inferred as String
The *before* the return type declares the type parameter.> — T must implement Comparable.
public static <T extends Comparable<T>> T max(List<T> list) {
T best = list.get(0);
for (T x : list) if (x.compareTo(best) > 0) best = x;
return best;
}
Note: extends here means *extends or implements* — the same keyword for classes and interfaces.List extends Number> — producer of Number. You can READ Numbers from it. You CANNOT add (except null), because the actual type might be ListList super Integer> — consumer of Integer. You can WRITE Integers into it. Reading gives back Object.public static double sum(List<? extends Number> nums) { // producer
double total = 0;
for (Number n : nums) total += n.doubleValue();
return total;
}public static void addInts(List<? super Integer> dst) { // consumer
dst.add(1);
dst.add(2);
}
List and List are both just List. Consequences:new T[10] or new T().if (x instanceof List) — only instanceof List.List, not List.