Without generics, a container class like ArrayList would store raw Object references. You'd need to cast every element you retrieve, and a wrong cast would crash at runtime.
Generics let you declare a type parameter:
public class Box<T> {
private T item;
public void set(T item) { this.item = item; }
public T get() { return item; }
}
Now the compiler enforces type safety:
Box<String> box = new Box<>();
box.set("hello");
String value = box.get(); // no cast needed
If you accidentally call box.set(42) on a Box<String>, the compiler stops you before the code ever runs. That is the whole point: catch type errors at compile time, not at runtime.