Type Casting & Wrapper Classes
Widening (implicit) casting automatically converts a smaller type into a bigger one — like int to double, with no loss.
Narrowing (explicit) casting requires manually converting a bigger type into a smaller one — like double to int — and some data (the decimal part) can be lost.
Wrapper classes (Integer, Double, Character, Boolean) let you use primitive types as objects. Autoboxing automatically turns a primitive into its wrapper; unboxing does the reverse.
double d = 100.99;
int i = (int) d; // narrowing, i = 100
int x = 5;
Integer boxed = x; // autoboxing
int y = boxed; // unboxingWidening automatic hai aur is order mein chalti hai: byte → short → int → long → float → double (char bhi seedha int mein widen ho sakta hai). Har step mein data safe rehta hai, koi loss nahi hota, isliye Java khud kar deta hai bina explicit cast maange — compiler ko pata hai ki chhoti value badi jagah aasani se fit ho jaayegi.
Interesting edge case: int se float mein widening technically "safe" mani jaati hai (koi compile error nahi), lekin bahut precision loss ho sakta hai bade numbers ke liye — kyunki float sirf ~7 significant decimal digits store kar sakta hai, jabki int 10 digits tak ja sakta hai. Ye ek jagah hai jaha "widening = koi data loss nahi" ka general rule thoda toot jaata hai.
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 maangta hai kyunki data loss ho sakta hai — Java tumse explicitly (targetType) likhwata hai taaki tum "jaan-boojh kar" ye risk le rahe ho, galti se nahi.
double se int cast karne par decimal part poori tarah "truncate" (kaat) hota hai, round nahi hota — 9.99 se 9 milega, na ki 10. Agar rounding chahiye, Math.round() use karo cast karne se pehle.
Agar value target type ke range se bahar ho, "overflow" ho jaata hai — number wrap around karke ajeeb (often negative) value de deta hai. Ye silently hota hai, koi exception nahi aati — isliye bahut dangerous bug source hai agar dhyan na diya jaaye.
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)Har primitive ka wrapper class hai: int→Integer, double→Double, char→Character, boolean→Boolean, long→Long, etc. Ye object ki tarah use karne dete hain (jaise Collections mein, jo sirf objects store karti hain, primitives nahi) — List<int> possible nahi hai, List<Integer> hai.
Autoboxing automatically primitive ko wrapper mein convert kar deta hai (int → Integer), Unboxing ulta karta hai (Integer → int) — Java 5 se ye automatic hai, pehle manually Integer.valueOf()/intValue() call karna padta tha.
Integer.parseInt("123") String ko int primitive banata hai. Integer.valueOf("123") String ko Integer object banata hai. Dono common hain, farak sirf return type ka hai.
Interesting trivia: Java -128 se 127 tak ke Integer objects ko cache karke rakhta hai (memory bachane ke liye, kyunki chhote numbers bahut common hote hain). Isliye Integer a = 100; Integer b = 100; ke liye a == b true deta hai (cache se same object), lekin 200 ke liye false (do alag objects bante hain)!
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)