Type Casting and Type Conversion in Java

Widening happens by itself, narrowing needs a cast and can lose data, and casting a reference only changes how the compiler sees an object.

What conversion means

Java converts a value from one type to another in two situations: when the compiler can prove that nothing is lost, and when you explicitly take responsibility with a cast.

Widening conversion

A smaller type fits inside a larger one, so the conversion is automatic.

byte -> short -> int -> long -> float -> double
             char -> int
int units = 250;
long total = units;      // widening, no cast needed
double rate = total;     // widening again
Widening from long to float is automatic but not lossless. A 64 bit integer can carry more significant digits than a 32 bit float can represent, so precision may still be lost.

Narrowing conversion

Going the other way may not fit, so the compiler demands an explicit cast.

double price = 249.99;
int rupees = (int) price;      // 249, the fraction is discarded not rounded

int large = 300;
byte small = (byte) large;     // 44, the extra bits are simply dropped

Narrowing an integer type keeps only the low order bits. The result is well defined, but it is rarely what was intended.

Numeric promotion in expressions

Before arithmetic, operands are promoted. Anything smaller than int becomes int, and if either operand is larger, both are promoted to the larger type.

byte a = 10, b = 20;
// byte sum = a + b;        // compile error: a + b is an int
byte sum = (byte) (a + b);  // explicit and correct

System.out.println(1 / 2);        // 0   both operands are int
System.out.println(1 / 2.0);      // 0.5 the int is promoted to double

Overflow

int max = Integer.MAX_VALUE;
System.out.println(max + 1);   // a large negative number, silently

// Fail loudly instead
System.out.println(Math.addExact(max, 1));   // throws ArithmeticException

Integer overflow does not throw by default; it wraps around. The Math.addExact family exists for arithmetic where wrapping would be a serious bug.

char and int

char grade = 66;
System.out.println(grade);           // B
System.out.println((int) grade);     // 66
System.out.println(grade + 1);       // 67, because char is promoted to int

Casting references

A reference cast never changes the object. It changes only the type through which the compiler lets you view it.

Object value = "a text value";      // upcast, always safe, implicit

String text = (String) value;       // downcast, checked at runtime
Integer wrong = (Integer) value;    // compiles, throws ClassCastException

The safe form combines the test and the cast in one step, using pattern matching for instanceof from Java 16:

if (value instanceof String text) {
    System.out.println(text.length());
}

Strings are not converted by casting

String input = "42";
// int n = (int) input;             // will not compile
int n = Integer.parseInt(input);    // parsing, not casting
String back = String.valueOf(n);    // or Integer.toString(n)

Common mistakes

  • Expecting (int) to round. It truncates towards zero. Use Math.round to round.
  • Writing long ms = 24 * 60 * 60 * 1000 * 1000; and overflowing before the assignment. Make the first operand a long.
  • Downcasting without checking the actual type first.
  • Believing a cast can convert unrelated types. It cannot; only a real subtype relationship works.

Best practices

  • Let widening happen naturally, and treat every cast as a claim you must justify.
  • Use pattern matching for instanceof instead of a separate test and cast.
  • Use Math.toIntExact and the Exact methods where silent overflow would be dangerous.

Practice

  1. What does System.out.println((int) -2.7); print, and why is it not -3?
  2. Fix long nanos = 1000 * 1000 * 1000 * 10; so it holds the intended value.
  3. Explain why Object o = new int[3]; compiles.
  4. Write a method that safely converts an Object to a String, returning a default when the type does not match.

Conclusion

Widening is automatic, narrowing is a deliberate cast that can lose data, and reference casting only reinterprets an existing object. Treat every cast you write as a promise the runtime will check.

Topics #Beginner #Java
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Java notes →
Java

Introduction to Java

Java is a statically typed, object oriented language that compiles to bytecode and runs on a virtual machine, which is what makes it portable.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.