Type Casting in Java


The idea in one line

Casting tells the compiler to treat a value as a different type.

  • For primitives, casting converts the value (possible data loss).
  • For references (objects), casting does not change the objectβ€”only the view type (unsafe casts can throw ClassCastException).

1) Primitive casting

Widening (safe, implicit)

Small β†’ big: byte β†’ short β†’ int β†’ long β†’ float β†’ double, and char β†’ int.
No precision loss for integer widening (but long β†’ float may lose precision due to float’s format).

int i = 42;
long L = i;        // OK: widening
double d = L;      // OK: widening
char c = 'A';
int code = c;      // 65

Narrowing (unsafe, explicit)

Big β†’ small must be cast; may overflow or truncate.

double price = 10.99;
int iprice = (int) price;     // 10 (fraction truncated)

int big = 130;
byte b = (byte) big;          // -126 (overflow wraps around)

Numeric promotion in expressions

Smaller types promote to int in arithmetic.

byte x = 10, y = 20;
// x + y is int, not byte
byte z = (byte) (x + y);      // cast required

2) Reference casting (objects)

Upcasting (safe, implicit)

Subclass β†’ superclass (or interface) is automatic.

Dog dog = new Dog();
Animal a = dog;        // upcast: always safe
Runnable r = dog;      // to an implemented interface: safe

Downcasting (explicit, may fail)

Superclass β†’ subclass needs a cast and is only safe if the object really is that subclass.

Animal a = new Dog();        // actual object is Dog
Dog d = (Dog) a;             // OK at runtime

Animal a2 = new Cat();
Dog d2 = (Dog) a2;           // ClassCastException at runtime

Always check first:

if (a2 instanceof Dog d3) {   // pattern matching (Java 16+)
    d3.bark();
}

Tip: prefer polymorphism (virtual methods) to avoid downcasts.


3) Generics, arrays, and wrappers

  • Generics are invariant: List<String> is not a List<Object>.

    List<String> ls = new ArrayList<>();
    // List<Object> lo = ls;         // compile-time error
    List<? extends Object> lo = ls;  // OK (read-only intent)
    

    Avoid unchecked casts; use wildcards.

  • Arrays are covariant: String[] is a subtype of Object[], but you might get ArrayStoreException at runtime if you store the wrong type.

  • Wrappers & Number: you can’t cast unrelated wrappers:

    Integer I = 5;
    // Double D = (Double) (Object) I;   // runtime ClassCastException
    Number n = I;
    double dv = n.doubleValue();         // use Number’s methods
    

4) Overload selection & casts

Casts can change which overloaded method is chosen (most specific applicable method wins).

void f(long x) { }
void f(Integer x) { }
f(5);           // chooses f(long) (primitive int β†’ long)
f((Integer)5);  // chooses f(Integer)

5) Runnable β€œall-in-one” demo (Java 17)

Save as Main.java:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        // ---- Primitive casting ----
        double price = 10.99;
        int iprice = (int) price;           // 10
        System.out.println("Primitive narrowing: (int)10.99 -> " + iprice);

        int big = 130;
        byte b = (byte) big;                // -126 due to overflow
        System.out.println("Overflow on narrowing: (byte)130 -> " + b);

        char c = 'A';
        int code = c;                       // 65
        System.out.println("Widening char->int: 'A' -> " + code);

        byte x = 10, y = 20;
        byte z = (byte) (x + y);            // expression promotes to int
        System.out.println("Promotion in expr: (byte)(10+20) -> " + z);

        // ---- Reference casting ----
        Animal a = new Dog();               // upcast (implicit)
        a.speak();                          // "woof"
        if (a instanceof Dog d) {           // safe downcast via pattern match
            d.bark();
        }

        Animal a2 = new Cat();
        try {
            Dog wrong = (Dog) a2;           // will throw ClassCastException
            wrong.bark();
        } catch (ClassCastException ex) {
            System.out.println("Caught bad downcast: " + ex);
        }

        // ---- Interfaces ----
        Runnable r = new Dog();             // upcast to interface
        r.run();

        // ---- Arrays covariance pitfall ----
        try {
            Object[] arr = new String[2];   // covariant assignment
            arr[0] = 123;                   // ArrayStoreException at runtime
        } catch (ArrayStoreException ex) {
            System.out.println("ArrayStoreException: " + ex.getMessage());
        }

        // ---- Generics invariance ----
        List<String> ls = List.of("a", "b");
        List<? extends Object> lo = ls;     // read-only view with wildcard
        System.out.println("Generics invariance: size=" + lo.size());

        // ---- Wrappers & Number ----
        Number n = Integer.valueOf(42);
        double dv = n.doubleValue();        // use Number API, not casts
        System.out.println("Number.doubleValue(): " + dv);

        // ---- Overload selection ----
        OverloadDemo od = new OverloadDemo();
        od.f(5);             // chooses f(long)
        od.f((Integer) 5);   // chooses f(Integer)
    }
}

abstract class Animal { void speak() { System.out.println("..."); } }
class Dog extends Animal implements Runnable {
    @Override void speak() { System.out.println("Dog: woof"); }
    void bark() { System.out.println("Dog barks"); }
    @Override public void run() { System.out.println("Dog runs"); }
}
class Cat extends Animal { @Override void speak() { System.out.println("Cat: meow"); } }

class OverloadDemo {
    void f(long x) { System.out.println("f(long): " + x); }
    void f(Integer x) { System.out.println("f(Integer): " + x); }
}

Compile & run:

javac --release 17 Main.java
java Main

Quick best practices

  • Prefer polymorphism over downcasting.
  • For primitives, avoid narrowing unless necessary; watch for truncation/overflow.
  • With generics, use wildcards instead of unchecked casts.
  • Use instanceof (pattern matching in Java 16+) before downcasting.
  • For numeric wrappers, use Number methods (intValue(), doubleValue(), …), not cross-wrapper casts.
Back to blog

Leave a comment

Please note, comments need to be approved before they are published.