Widening Conversion
Widening Conversion (Implicit)
Widening converts a smaller type to a larger type. It happens automatically without data loss.
Widening Chain
byte → short → int → long → float → double
char → int → long → float → double
Examples
public class Widening {
public static void main(String[] args) {
// byte to short
byte b = 10;
short s = b; // implicit widening
// short to int
int i = s; // implicit widening
// int to long
long l = i; // implicit widening
// long to float
float f = l; // implicit (may lose precision!)
// float to double
double d = f; // implicit widening
// char to int
char c = 'A';
int charToInt = c; // implicit (65)
System.out.println("All widening conversions work!");
System.out.println("char 'A' to int: " + charToInt); // 65
}
}
Why Widening is Safe
// No data loss because target type can represent all source values
byte small = 127; // fits in 8 bits
int big = small; // fits easily in 32 bits
long bigger = big; // fits easily in 64 bits
// Exception: long to float may lose precision
long precise = 123456789L;
float imprecise = precise; // may lose some precision
System.out.println(precise); // 123456789
System.out.println(imprecise); // 1.23456792E8 (approximation)
Auto-boxing (Primitive to Wrapper)
// Java automatically converts primitives to wrapper objects
int primitive = 42;
Integer wrapped = primitive; // auto-boxing
// Works for all primitives
Double d = 3.14; // double to Double
Boolean b = true; // boolean to Boolean
Character c = 'A'; // char to Character
// In collections
List<Integer> list = new ArrayList<>();
list.add(42); // auto-boxing: int to Integer
// Unboxing (wrapper to primitive)
Integer obj = 100;
int value = obj; // auto-unboxing
Narrowing Conversion
Narrowing Conversion (Explicit)
Narrowing converts a larger type to a smaller type. Requires explicit cast and may lose data.
Narrowing Chain
double → float → long → int → short → byte
Examples
public class Narrowing {
public static void main(String[] args) {
// double to int (truncates)
double d = 3.99;
int i = (int) d; // 3 (truncates, not rounds)
// int to byte (may overflow)
int big = 130;
byte small = (byte) big; // -126 (overflow!)
// long to int (may truncate)
long l = 3000000000L;
int truncated = (int) l; // -1294967296 (overflow!)
// float to int
float f = 9.99f;
int fromFloat = (int) f; // 9
// double to float (precision loss)
double precise = 3.141592653589793;
float imprecise = (float) precise;
System.out.println(precise); // 3.141592653589793
System.out.println(imprecise); // 3.1415927
System.out.println("Narrowing conversions:");
System.out.println("3.99 → int: " + i); // 3
System.out.println("130 → byte: " + small); // -126
}
}
Safe Narrowing Techniques
// 1. Range check before casting
public byte safeCastToByte(int value) {
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new ArithmeticException("Value out of byte range");
}
return (byte) value;
}
// 2. Math.round for rounding
public int roundDouble(double d) {
return (int) Math.round(d); // 3.99 → 4, 3.49 → 3
}
// 3. Clamp to range
public int clamp(int value, int min, int max) {
return Math.max(min, Math.min(max, value));
}
// 4. Use appropriate methods
String numStr = "42";
int parsed = Integer.parseInt(numStr); // safe parsing
// 5. Check before casting
long bigLong = Long.MAX_VALUE;
if (bigLong <= Integer.MAX_VALUE) {
int safeInt = (int) bigLong; // safe
}
Data Loss Scenarios
// 1. Truncation
double pi = 3.14159;
int truncated = (int) pi; // 3 (decimal lost)
// 2. Overflow
int tooBig = 200;
byte overflow = (byte) tooBig; // -56
// 3. Precision loss
float f = 123456789.0f;
int fromFloat = (int) f; // 123456790 (precision lost)
// 4. Sign change
int negative = -1;
char asChar = (char) negative; // 65535 (unsigned interpretation)
Object Casting
Upcasting (Implicit)
Converting a subclass reference to a superclass reference. Always safe.
// Upcasting: Child → Parent (implicit)
public class Animal {
public void speak() {
System.out.println("Animal speaks");
}
}
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
public void fetch() {
System.out.println("Fetching ball");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
// Upcasting (implicit)
Animal animal = dog; // OK, always safe
animal.speak(); // Woof! (polymorphism)
// animal.fetch(); // ERROR: fetch() not in Animal
}
}
Downcasting (Explicit)
Converting a superclass reference to a subclass reference. Requires explicit cast and may fail at runtime.
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // upcasted
// Downcasting (explicit)
Dog dog = (Dog) animal; // OK, animal is actually a Dog
dog.fetch(); // Works!
// Dangerous downcast
Animal cat = new Animal();
// Dog notCat = (Dog) cat; // ClassCastException at runtime!
}
}
instanceof Check
// Always check before downcasting
public class Main {
public static void main(String[] args) {
Animal animal = getAnimal(); // could be Dog, Cat, etc.
// Safe downcasting with instanceof
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.fetch();
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.purr();
}
// Pattern matching (Java 16+)
if (animal instanceof Dog dog) {
dog.fetch(); // no explicit cast needed
}
}
}
Interface Casting
public interface Flyable {
void fly();
}
public interface Swimmable {
void swim();
}
public class Duck implements Flyable, Swimmable {
public void fly() { System.out.println("Flying"); }
public void swim() { System.out.println("Swimming"); }
}
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
// Upcast to interface
Flyable flyer = duck;
flyer.fly(); // OK
Swimmable swimmer = duck;
swimmer.swim(); // OK
// Check interface
if (duck instanceof Flyable) {
((Flyable) duck).fly(); // safe downcast
}
}
}
Casting Summary
| Cast Type | Direction | Safety | Example |
|---|---|---|---|
| Widening | Small → Large | Always safe | int → long |
| Narrowing | Large → Small | May lose data | double → int |
| Upcasting | Child → Parent | Always safe | Dog → Animal |
| Downcasting | Parent → Child | May throw ClassCastException | Animal → Dog |
Practice Problems
What is the output of this code?
Example:
Input: public class Test { public static void main(String[] args) { double d = 7.99; int i = (int) d; System.out.println(i); } }
Output: 7
Casting double to int truncates the decimal part, giving 7.
Optimal Solution — O(1) time, O(1) space
Understand truncation behavior
public class Test {
public static void main(String[] args) {
double d = 7.99;
int i = (int) d; // truncates to 7
System.out.println(i); // 7
}
}Edge Cases:
- Rounding vs truncation
- Negative values
What is the output of this code?
Example:
Input: public class Test { public static void main(String[] args) { int big = 256; byte small = (byte) big; System.out.println(small); } }
Output: 0
256 in binary is 100000000. When cast to byte (8 bits), only 00000000 remains, which is 0.
Optimal Solution — O(1) time, O(1) space
Understand binary overflow
public class Test {
public static void main(String[] args) {
int big = 256; // binary: 100000000
byte small = (byte) big; // keeps last 8 bits: 00000000
System.out.println(small); // 0
}
}Edge Cases:
- Negative overflow
- Byte range -128 to 127
Quiz
1. Which type conversion requires explicit casting?
2. What is the result of (int) 3.7?
3. What is upcasting in Java?
4. What is the primary purpose of Type Casting?
Flashcards
Question
What is widening conversion?
Click to reveal answer
Answer
Converting a smaller type to a larger type (e.g., int to long). Happens implicitly, no data loss.
Question
What is narrowing conversion?
Click to reveal answer
Answer
Converting a larger type to a smaller type (e.g., double to int). Requires explicit cast, may lose data.
Question
What is the difference between upcasting and downcasting?
Click to reveal answer
Answer
Upcasting: Child → Parent (implicit, safe). Downcasting: Parent → Child (explicit, may throw ClassCastException).
Question
What is Type Casting?
Click to reveal answer
Answer
Type Casting is a key concept in Java programming.
Question
When to use Type Casting?
Click to reveal answer
Answer
Use Type Casting when building production systems that require reliability, scalability, and maintainability.
Revision Notes
Key Takeaways
- 1.Widening is implicit and safe, narrowing requires explicit casting
- 2.Casting double to int truncates (3.99 → 3), does not round
- 3.Integer overflow happens silently when narrowing
- 4.Upcasting is always safe, downcasting may throw ClassCastException
- 5.Use instanceof before downcasting to prevent runtime errors
Interview Tips
- •Know the widening conversion chain
- •Understand truncation vs rounding in casting
- •Explain upcasting and downcasting with examples
- •Use instanceof for safe downcasting
Cheat Sheet
Type Casting Cheat Sheet
Widening (implicit):
byte → short → int → long → float → double
No data loss, happens automatically
Narrowing (explicit):
double → float → long → int → short → byte
Requires cast: (int) 3.99 → 3
Object Casting:
- Upcasting: Child → Parent (implicit, safe)
- Downcasting: Parent → Child (explicit, may fail)
- Always use instanceof before downcasting
Auto-boxing:
int → Integer (automatic)
Integer → int (automatic unboxing)