Generics
Generics <T> से हम classes/methods को "किसी भी type के लिए काम करने वाला" बना सकते हैं, बिना अलग-अलग versions लिखे।
Compile-time पर type-safety मिलती है — ग़लत type डालने की कोशिश पर compiler तुरंत error दे देता है, run-time crash से बचा लेता है।
class Box<T> {
T item;
void set(T item) { this.item = item; }
T get() { return item; }
}
Box<String> b = new Box<>();
b.set("Hello");Sirf classes nahi, individual methods bhi generic ho sakte hain — apna khud ka type parameter define karke, chahe class generic na ho. Method definition mein <T> return type se pehle likhte hain.
static <T> T firstElement(List<T> list) {
return list.get(0);
}<T extends Number> ka matlab hai T sirf Number ya uski subclasses (Integer, Double, etc.) ho sakti hai — isse tum T par Number ke methods (jaise .doubleValue()) call kar sakte ho, jo warna allowed nahi hota (compiler ko pata nahi hota T ke paas ye method hai ya nahi, jab tak bound na diya jaaye).
static <T extends Number> double sum(List<T> list) {
double total = 0;
for (T item : list) total += item.doubleValue(); // Number ka method
return total;
}? extends Type ka matlab "Type ya uski koi subclass" (read-only use ke liye achha — "producer", tum ise padh sakte ho lekin add nahi kar sakte kyunki compiler exact type nahi jaanta). ? super Type ka matlab "Type ya uski koi superclass" (write ke liye achha — "consumer"). Ye "PECS" principle kehlata hai: Producer Extends, Consumer Super.
void printAll(List<? extends Number> list) { // read-only OK
for (Number n : list) System.out.println(n);
}Java generics compile-time feature hain — runtime par generic type information "erase" (mita) ho jaati hai, backward compatibility ke liye (purana Java code, jo generics se pehle likha gaya tha, bina modify kiye naye JVM par bhi chal sake). Isi wajah se List<String> aur List<Integer> runtime par same class (List) dikhte hain, aur tum new T() jaisa direct instantiation nahi kar sakte (JVM ko pata hi nahi T kya hai runtime par).