Skip to content
beginnerPhase 9 · Java Foundations

Type Casting

Master widening, narrowing, and explicit type casting in Java.

30m
2 problems
Topic Progress0%

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

0/2solved
Predict Output: Narrowing Cast
Type Casting

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
Predict Output: Overflow Cast
Integer Overflow

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?

Question 1 options

2. What is the result of (int) 3.7?

Question 2 options

3. What is upcasting in Java?

Question 3 options

4. What is the primary purpose of Type Casting?

Question 4 options

Flashcards

Question

What is widening conversion?

Answer

Converting a smaller type to a larger type (e.g., int to long). Happens implicitly, no data loss.

Question

What is narrowing conversion?

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?

Answer

Upcasting: Child → Parent (implicit, safe). Downcasting: Parent → Child (explicit, may throw ClassCastException).

Question

What is Type Casting?

Answer

Type Casting is a key concept in Java programming.

Question

When to use Type Casting?

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)