Java generics move many type errors to compilation. Bounds and wildcards describe which producers and consumers are accepted without falling back to unsafe raw types.
Express Java type relationships with parameters, bounds, and wildcards so reusable APIs remain checked without raw types or unsafe casts.
Before generics, code often stored Object and required manual casts. Generics make the expected type part of the declaration.
import java.util.ArrayList;
import java.util.List;
public class GenericListDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Asha");
String first = names.get(0); // no cast needed
System.out.println(first.toUpperCase());
}
}
Create a generic class when the same logic should work with different types. Create a generic method when only one method needs type flexibility.
class Box<T> {
private T value;
void set(T value) {
this.value = value;
}
T get() {
return value;
}
}
public class GenericMethodDemo {
static <T> void printArray(T[] values) {
for (T value : values) {
System.out.println(value);
}
}
}
Bounds restrict the type parameter. Wildcards allow flexible method parameters when exact generic types differ.
public class BoundedGenericDemo {
static <T extends Number> double sum(T a, T b) {
return a.doubleValue() + b.doubleValue();
}
}
Java implements generics using type erasure. Generic type information is checked at compile time but mostly removed at runtime.
Generics let the compiler check element types before runtime. A List<String> communicates intent and prevents accidental insertion of Integer, Student, or other unrelated values.
Generics let a class, interface, or method work with a type chosen by the caller while still keeping compile-time type safety. Without generics, collections can accept Object values and mistakes may appear later as ClassCastException. With generics, Java checks the expected type before the program runs.
The most important idea is that T, E, K, and V are placeholders, not special data types. They are replaced by real types such as String, Integer, Student, or Product when the generic code is used. Bounded generics add one more rule: they allow only types that extend a certain class or implement a certain interface.
static <T> void printItems(List<T> items) {
for (T item : items) {
System.out.println(item);
}
}
printItems(List.of("Java", "Spring"));
They discard compile-time type checks and can move failures to runtime casts.
It accepts a producer of Number subtypes, but adding values is restricted.
It accepts Integer values into a consumer whose element type is Integer or a superclass.
Practice, interview questions, and compiler links for Core Java.
Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.
Explore 500+ free tutorials across 20+ languages and frameworks.
Fresh tutorials, interview guides, and coding practice in your inbox.