Type Casting और Wrapper Classes
Widening (implicit) casting में छोटा type बड़े type में ख़ुद-ब-ख़ुद convert हो जाता है — जैसे int से double, कुछ loss नहीं होता।
Narrowing (explicit) casting में बड़ा type छोटे में manually convert करना पड़ता है — जैसे double से int, कुछ data (decimal part) खो सकता है।
Wrapper classes (Integer, Double, Character, Boolean) primitive types को object की तरह use करने देते हैं। Autoboxing primitive को wrapper में बदल देता है automatically, unboxing उल्टा करता है।
double d = 100.99;
int i = (int) d; // narrowing, i = 100
int x = 5;
Integer boxed = x; // autoboxing
int y = boxed; // unboxing- Widening: automatic, छोटा->बड़ा
- Narrowing: manual, बड़ा->छोटा, data loss possible
- Autoboxing/Unboxing: primitive <-> wrapper
Widening automatic है और इस order में चलती है: byte → short → int → long → float → double (char भी सीधा int में widen हो सकता है)। हर step में data safe रहता है, कोई loss नहीं होता, इसलिए Java ख़ुद कर देता है बिना explicit cast माँगे — compiler को पता है कि छोटी value बड़ी जगह आसानी से fit हो जाएगी।
Interesting edge case: int से float में widening technically "safe" मानी जाती है (कोई compile error नहीं), लेकिन बहुत precision loss हो सकता है बड़े numbers के लिए — क्योंकि float सिर्फ़ ~7 significant decimal digits store कर सकता है, जबकि int 10 digits तक जा सकता है। ये एक जगह है जहाँ "widening = कोई data loss नहीं" का general rule थोड़ा टूट जाता है।
byte b = 10;
long l = b; // automatic
double d = l; // automatic
int bigInt = 123456789;
float f = bigInt; // widening, but PRECISION loss ho sakta hai!Narrowing manual cast माँगता है क्योंकि data loss हो सकता है — Java तुमसे explicitly (targetType) लिखवाता है ताकि तुम "जान-बूझकर" ये risk ले रहे हो, ग़लती से नहीं।
double से int cast करने पर decimal part पूरी तरह "truncate" (कट) होता है, round नहीं होता — 9.99 से 9 मिलेगा, ना कि 10। अगर rounding चाहिए, Math.round() use करो cast करने से पहले।
अगर value target type के range से बाहर हो, "overflow" हो जाता है — number wrap around करके अजीब (often negative) value दे देता है। ये silently होता है, कोई exception नहीं आती — इसलिए बहुत dangerous bug source है अगर ध्यान ना दिया जाए।
double d = 9.99;
int i = (int) d; // 9 (decimal cut gaya, round nahi hua)
int rounded = (int) Math.round(d); // 10 (agar rounding chahiye)
int big = 130;
byte b = (byte) big; // -126 (overflow! byte ka max 127 hai)हर primitive का wrapper class है: int→Integer, double→Double, char→Character, boolean→Boolean, long→Long, etc। ये object की तरह use करने देते हैं (जैसे Collections में, जो सिर्फ़ objects store करती हैं, primitives नहीं) — List<int> possible नहीं है, List<Integer> है।
Autoboxing automatically primitive को wrapper में convert कर देता है (int → Integer), Unboxing उल्टा करता है (Integer → int) — Java 5 से ये automatic है, पहले manually Integer.valueOf()/intValue() call करना पड़ता था।
Integer.parseInt("123") String को int primitive बनाता है। Integer.valueOf("123") String को Integer object बनाता है। दोनों common हैं, फ़र्क़ सिर्फ़ return type का है।
Interesting trivia: Java -128 से 127 तक के Integer objects को cache करके रखता है (memory बचाने के लिए, क्योंकि छोटे numbers बहुत common होते हैं)। इसलिए Integer a = 100; Integer b = 100; के लिए a == b true देता है (cache से same object), लेकिन 200 के लिए false (दो अलग objects बनते हैं)!
Integer a = 100, b = 100;
System.out.println(a == b); // true (cached)
Integer x = 200, y = 200;
System.out.println(x == y); // false! (not cached)
System.out.println(x.equals(y)); // true (सही tarika)