🔄
Basics

Type Casting & Wrapper Classes

Converting Types
💡 Type casting is like pouring a small glass of water into a bigger glass (widening), or forcing a big glass of water into a small one (narrowing — some might spill).

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;        // unboxing
🔄
Type casting is like pouring a small glass of water into a bigger glass (widening), or forcing a big glass of water into a small one (narrowing — some might spill).
1 / 4
⚡ Quick Recap
  • Widening: automatic, small->big
  • Narrowing: manual, big->small, possible data loss
  • Autoboxing/Unboxing: primitive <-> wrapper
On this page (3 subtopics)

Widening is automatic and follows this order: byte → short → int → long → float → double (char can also widen directly into int). Data stays safe at every step, no loss occurs, so Java does it automatically without asking for an explicit cast — the compiler knows a smaller value will easily fit into a bigger space.

Interesting edge case: widening from int to float is technically considered "safe" (no compile error), but can lose a lot of precision for large numbers — because a float can only store ~7 significant decimal digits, while an int can go up to 10 digits. This is one place where the general rule "widening = no data loss" breaks down a bit.

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 requires a manual cast because data can be lost — Java makes you write (targetType) explicitly, so you're taking this risk "on purpose", not by accident.

Casting double to int completely "truncates" (chops off) the decimal part, it doesn't round — 9.99 becomes 9, not 10. If you need rounding, use Math.round() before the cast.

If a value is outside the target type's range, "overflow" happens — the number wraps around and gives a strange (often negative) value. This happens silently, no exception is thrown — which is why it's a very dangerous bug source if you're not careful.

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)
⚠️Common Mistake: A narrowing cast doesn't throw any exception on overflow — it silently gives a wrong value. Always check that the target type's range is big enough, especially when casting external/user input.

Every primitive has a wrapper class: int→Integer, double→Double, char→Character, boolean→Boolean, long→Long, etc. These let you use them as objects (like in Collections, which only store objects, not primitives) — List<int> isn't possible, but List<Integer> is.

Autoboxing automatically converts a primitive into its wrapper (int → Integer), Unboxing does the reverse (Integer → int) — this has been automatic since Java 5; before that you had to manually call Integer.valueOf()/intValue().

Integer.parseInt("123") turns a String into an int primitive. Integer.valueOf("123") turns a String into an Integer object. Both are common, the only difference is the return type.

Interesting trivia: Java caches Integer objects from -128 to 127 (to save memory, since small numbers are very common). So for Integer a = 100; Integer b = 100;, a == b gives true (same cached object), but for 200 it gives false (two separate objects get created)!

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)
⚠️Common Mistake: Never compare wrapper objects with == (== is fine only for primitives like int/double) — always use .equals(). The Integer cache's "sometimes works" behavior creates bugs that are hard to catch.