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");- <T> से एक ही class कई types के लिए काम करती है
- Compile-time type safety मिलती है
- List<String>, Box<Integer> जैसे examples
सिर्फ़ classes नहीं, individual methods भी generic हो सकते हैं — अपना ख़ुद का type parameter define करके, चाहे class generic ना हो। Method definition में <T> return type से पहले लिखते हैं।
static <T> T firstElement(List<T> list) {
return list.get(0);
}<T extends Number> का मतलब है T सिर्फ़ Number या उसकी subclasses (Integer, Double, etc.) हो सकती है — इससे तुम T पर Number के methods (जैसे .doubleValue()) call कर सकते हो, जो वरना allowed नहीं होता (compiler को पता नहीं होता T के पास ये method है या नहीं, जब तक bound ना दिया जाए)।
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 का मतलब "Type या उसकी कोई subclass" (read-only use के लिए अच्छा — "producer", तुम इसे पढ़ सकते हो लेकिन add नहीं कर सकते क्योंकि compiler exact type नहीं जानता)। ? super Type का मतलब "Type या उसकी कोई superclass" (write के लिए अच्छा — "consumer")। ये "PECS" principle कहलाता है: 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 हैं — runtime पर generic type information "erase" (मिटा) हो जाती है, backward compatibility के लिए (पुराना Java code, जो generics से पहले लिखा गया था, बिना modify किए नए JVM पर भी चल सके)। इसी वजह से List<String> और List<Integer> runtime पर same class (List) दिखते हैं, और तुम new T() जैसा direct instantiation नहीं कर सकते (JVM को पता ही नहीं T क्या है runtime पर)।