Java Tutorial
Java Generics
Generics parameterize types — List<String> holds strings, Box<T> holds whatever T you plug in — and the compiler checks it.
Type parameters on collections
Write the element type in angle brackets. After erasure at runtime the JVM sees raw objects, but at compile time javac refuses the wrong type — that is the whole point.
Example
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List names = new ArrayList<>();
names.add("Ada");
// names.add(3); // error: incompatible types
String first = names.get(0);
System.out.println(first);
}
} Your own generic class
Declare class Box<T> and use T as a stand-in type. Callers pick the real type when they construct the box.
Example
class Box {
private T value;
void set(T value) { this.value = value; }
T get() { return value; }
}
public class Main {
public static void main(String[] args) {
Box box = new Box<>();
box.set(42);
System.out.println(box.get());
}
} Generic methods
A method can introduce its own type parameter before the return type. Useful for helpers that work on any list or pair of values.
Example
import java.util.List;
public class Main {
static T first(List list) {
return list.get(0);
}
public static void main(String[] args) {
System.out.println(first(List.of("a", "b")));
System.out.println(first(List.of(10, 20)));
}
} The diamond new ArrayList<>() lets the compiler infer the type argument from the left side. You still declare the full type on the variable.
Bounds and wrappers
Type parameters must be reference types — use Integer, not int. A bound likeT extends Number restricts what callers may plug in.
Example
public class Main {
static double asDouble(T n) {
return n.doubleValue();
}
public static void main(String[] args) {
System.out.println(asDouble(3));
System.out.println(asDouble(2.5));
}
} Raw types (List without <...>) disable the checks. Always write the type argument in new code.
Try It Yourself
Exercise: Write a generic method last that returns the last element of a List<T>, then call it on a list of strings.
Show solution
import java.util.List;
static T last(List list) {
return list.get(list.size() - 1);
}
// in main:
System.out.println(last(List.of("red", "green", "blue"))); T is inferred from the list argument; the return type matches the element type.
Key Takeaways
- Generics let one class or method work with many types while staying type-safe at compile time.
- Use wrappers (
Integer) — type parameters cannot be primitives. - You can parameterize your own classes and methods with
<T>. - Bounds (
T extends Number) limit which types are allowed.
Worked examples
The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.
Open them in the Java editor at /java/try. Change one measurement and check whether the result still has the right unit.
Maths
A typed Box
Generics keep the type of the payload. Box of String cannot silently hold an Integer.
Example
class Box<T> {
private T value;
void set(T v) { value = v; }
T get() { return value; }
}
public class Main {
public static void main(String[] args) {
Box<Integer> b = new Box<>();
b.set(42);
System.out.println(b.get());
}
}