1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Widening (automatic): Small → large type (byte →int → long → float → double), no data loss.
- Narrowing (explicit cast): Large → small type, requires (type)value, may lose data! Type promotion: In expressions, smaller types promote to int (byte + byte → int).
- String conversion: Integer.parseInt("123") (String → int), String.valueOf(123) (int → String).
- Overflow: Exceeding range wraps around (127 + 1 = -128 for byte).
- Golden rule: Auto-widen, manually narrow. Always check for data loss when narrowing!
Think of pouring water. Widening = small cup → large bucket (no spill). Narrowing = large bucket → small cup (overflow!). Cast = carefully pour to avoid spill. Type promotion = measuring cups auto-convert to standard size. Overflow = water loops back!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Widening: Upgrade (economy → business class, always OK)
- Narrowing: Downgrade (requires confirmation, may lose perks)
- Overflow: Odometer rolling over (999,999 → 000,000)
- Type Promotion: Auto-format (handwriting → typed)
3. Technical Mastery (The "Deep Dive")
java
// ===========================================
// 1. WIDENING (Implicit/Automatic)
// ===========================================
// byte → short → int → long → float → double
// Smaller type automatically converts to larger
byte b = 10;
short s = b; // ✅ byte → short (automatic)
int i = s; // ✅ short → int (automatic)
long l = i; // ✅ int → long (automatic)
float f = l; // ✅ long → float (automatic)
double d = f; // ✅ float → double (automatic)
// Direct conversions
int num = 100;
long bigNum = num; // ✅ Automatic
double decimal = num; // ✅ Automatic (100.0)
// No data loss
byte small = 42;
int large = small; // ✅ 42 fits perfectly
// ===========================================
// 2. NARROWING (Explicit/Manual Cast)
// ===========================================
// Requires explicit cast: (targetType)value
// ⚠️ MAY LOSE DATA!
double d = 9.99;
int i = (int)d; // ✅ Explicit cast (i = 9, loses .99!)
long l = 1000L;
int i = (int)l; // ✅ Explicit cast
float f = 3.14f;
byte b = (byte)f; // ✅ Explicit cast (b = 3)
// ❌ Without cast
double price = 19.99;
int dollars = price; // ❌ Compile error! Narrowing requires cast
// ✅ With cast
int dollars = (int)price; // ✅ dollars = 19 (truncates decimal!)
// ===========================================
// 3. DATA LOSS IN NARROWING
// ===========================================
// ⚠️ Decimal truncation (not rounding!)
double value = 9.99;
int truncated = (int)value; // 9 (not 10!)
double negative = -5.7;
int result = (int)negative; // -5 (truncates toward zero)
// ⚠️ Overflow (value too large)
int large = 130;
byte small = (byte)large; // -126 (overflow!)
// Why? byte range: -128 to 127
// 130 wraps around: 130 - 256 = -126
int huge = 1000;
byte tiny = (byte)huge; // -24 (overflow!)
// ===========================================
// 4. TYPE PROMOTION IN EXPRESSIONS
// ===========================================
// In expressions, smaller types (byte, short, char) promote to int
byte b1 = 10;
byte b2 = 20;
byte b3 = b1 + b2; // ❌ Compile error!
// Why? b1 + b2 promotes to int!
// ✅ Fix 1: Use int
int result = b1 + b2; // ✅ result = 30
// ✅ Fix 2: Cast back to byte
byte b3 = (byte)(b1 + b2); // ✅ b3 = 30
// char promotion
char c1 = 'A'; // 65
char c2 = 'B'; // 66
int sum = c1 + c2; // 131 (65 + 66)
// Promotion hierarchy in expressions
byte + byte → int
short + short → int
byte + int → int
int + long → long
long + float → float
float + double → double
// ===========================================
// 5. STRING TO PRIMITIVE CONVERSION
// ===========================================
// String → primitive (parse methods)
String strNum = "123";
int num = Integer.parseInt(strNum); // 123
String strDouble = "3.14";
double d = Double.parseDouble(strDouble); // 3.14
String strBool = "true";
boolean b = Boolean.parseBoolean(strBool); // true
// Other parse methods
byte b = Byte.parseByte("10");
short s = Short.parseShort("100");
long l = Long.parseLong("1000");
float f = Float.parseFloat("3.14");
// ⚠️ NumberFormatException for invalid input
try {
int invalid = Integer.parseInt("abc"); // ❌ Throws exception!
} catch (NumberFormatException e) {
System.out.println("Invalid number format");
}
// ===========================================
// 6. PRIMITIVE TO STRING CONVERSION
// ===========================================
// Method 1: String.valueOf()
int num = 123;
String str1 = String.valueOf(num); // "123"
double d = 3.14;
String str2 = String.valueOf(d); // "3.14"
boolean b = true;
String str3 = String.valueOf(b); // "true"
// Method 2: Concatenation (simpler but less clear)
String str4 = num + ""; // "123"
String str5 = "" + d; // "3.14"
// Method 3: Wrapper toString()
String str6 = Integer.toString(num); // "123"
String str7 = Double.toString(d); // "3.14"
// ===========================================
// 7. WRAPPER CLASS CONVERSION (Autoboxing)
// ===========================================
// Primitive → Wrapper (autoboxing)
int primitive = 10;
Integer wrapper = primitive; // ✅ Auto-boxing
// Wrapper → Primitive (unboxing)
Integer wrapperObj = 20;
int primitiveValue = wrapperObj; // ✅ Auto-unboxing
// Manual boxing/unboxing (old way)
Integer manualBox = Integer.valueOf(30);
int manualUnbox = manualBox.intValue();
// ⚠️ NullPointerException risk
Integer nullWrapper = null;
int value = nullWrapper; // ❌ NullPointerException!
// ===========================================
// 8. OVERFLOW DEMONSTRATION
// ===========================================
// byte overflow example
byte max = 127;
byte overflow = (byte)(max + 1); // -128 (wraps around!)
System.out.println(max); // 127
System.out.println(overflow); // -128
// int overflow
int maxInt = Integer.MAX_VALUE; // 2,147,483,647
int overflowInt = maxInt + 1; // -2,147,483,648 (wraps!)
// Preventing overflow (use long)
long safe = (long)maxInt + 1; // 2,147,483,648 (correct!)5. The Comparison & Decision Layer
| Conversion | Type | Syntax | Data Loss? |
|---|---|---|---|
| Widening | Automatic | long l = 10; | No |
| Narrowing | Manual cast | int i = (int)10L; | Yes (possible) |
| String → int | Parse | Integer.parseInt("10") | Exception if invalid |
| int → String | valueOf | String.valueOf(10) | No |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question:
"Why does byte + byte result in int?"
Answer: Type promotion! In expressions, types smaller than int (byte, short, char) are automatically promoted to int.
java
byte b1 = 10;
byte b2 = 20;
byte b3 = b1 + b2; // ❌ Compile error!
// b1 + b2 promotes to int (not byte!)
// ✅ Fix 1: Store in int
int result = b1 + b2; // ✅
// ✅ Fix 2: Cast back to byte
byte b3 = (byte)(b1 + b2); // ✅Follow-up: "What happens when you cast 130 to byte?" Answer: Overflow! 130 becomes -126.
java
int large = 130;
byte small = (byte)large; // -126
// Calculation: 130 - 256 = -126
// byte range: -128 to 127
// Values wrap around like odometerPro-Tips:
- Check range before narrowing:
java
int value = 1000;
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
byte b = (byte)value; // Safe
} else {
System.out.println("Value out of range!");
}- Use
Math.toIntExact()to detect overflow:
java
long bigValue = 10_000_000_000L;
try {
int i = Math.toIntExact(bigValue); // Throws if overflow
} catch (ArithmeticException e) {
System.out.println("Overflow detected!");
}