Java Notes
Complete guide to type casting in Java — widening (implicit), narrowing (explicit), type promotion rules, object casting, autoboxing, and common pitfalls with practical examples.
Type casting is the process of converting a value from one data type to another. Java handles some conversions automatically (implicit) and requires explicit notation for others to prevent accidental data loss.
Two Types of Casting
Widening Casting (Implicit/Automatic)
Converting from a smaller type to a larger type happens automatically — no data loss is possible:
public class WideningCasting {
public static void main(String[] args) {
byte b = 42;
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)
System.out.println("byte: " + b);
System.out.println("short: " + s);
System.out.println("int: " + i);
System.out.println("long: " + l);
System.out.println("float: " + f);
System.out.println("double: " + d);
// Practical example
int itemCount = 150;
double averagePrice = 29.99;
double totalCost = itemCount * averagePrice; // int auto-promoted to double
System.out.printf("\nTotal: %d × $%.2f = $%.2f%n", itemCount, averagePrice, totalCost);
}
}byte: 42 short: 42 int: 42 long: 42 float: 42.0 double: 42.0 Total: 150 × $29.99 = $4498.50
Narrowing Casting (Explicit/Manual)
Converting from a larger type to a smaller type must be done explicitly — data might be lost:
public class NarrowingCasting {
public static void main(String[] args) {
double d = 9.78;
// Must explicitly cast (possible data loss!)
int i = (int) d; // Truncates decimal: 9
System.out.println("double " + d + " → int " + i);
int large = 130;
byte b = (byte) large; // Overflow! 130 wraps around
System.out.println("int " + large + " → byte " + b); // -126
long bigNum = 3_000_000_000L;
int smallerNum = (int) bigNum; // Data loss!
System.out.println("long " + bigNum + " → int " + smallerNum);
// char to int (widening) and int to char (narrowing)
char c = 'A';
int ascii = c; // char → int (automatic): 65
char back = (char) 66; // int → char (explicit): 'B'
System.out.println("char '" + c + "' → int " + ascii);
System.out.println("int 66 → char '" + back + "'");
// float to int truncates
float price = 19.99f;
int truncated = (int) price;
System.out.println("\nfloat " + price + " → int " + truncated + " (truncated, not rounded!)");
// To round instead of truncate:
int rounded = Math.round(price);
System.out.println("Math.round(" + price + ") = " + rounded);
}
}double 9.78 → int 9 int 130 → byte -126 long 3000000000 → int -1294967296 char 'A' → int 65 int 66 → char 'B' float 19.99 → int 19 (truncated, not rounded!) Math.round(19.99) = 20
Type Promotion in Expressions
Java automatically promotes smaller types in expressions:
public class TypePromotion {
public static void main(String[] args) {
// Rule 1: byte, short, char are promoted to int in expressions
byte a = 10, b = 20;
// byte c = a + b; // ERROR! result is int, not byte
int c = a + b; // OK
byte d = (byte)(a + b); // OK with explicit cast
System.out.println("byte + byte = int: " + c);
// Rule 2: If one operand is long, result is long
int x = 100;
long y = 200L;
long result1 = x + y; // int promoted to long
System.out.println("int + long = long: " + result1);
// Rule 3: If one operand is float, result is float
int m = 5;
float n = 2.5f;
float result2 = m + n; // int promoted to float
System.out.println("int + float = float: " + result2);
// Rule 4: If one operand is double, result is double
float f = 3.14f;
double dd = 2.0;
double result3 = f + dd; // float promoted to double
System.out.println("float + double = double: " + result3);
// Common gotcha: integer division
int p = 7, q = 2;
System.out.println("\n7 / 2 = " + (p / q)); // 3 (int / int = int)
System.out.println("7.0 / 2 = " + (7.0 / q)); // 3.5 (double / int = double)
System.out.println("(double)7 / 2 = " + ((double)p / q)); // 3.5
}
}byte + byte = int: 30 int + long = long: 300 int + float = float: 7.5 float + double = double: 5.140000104904175 7 / 2 = 3 7.0 / 2 = 3.5 (double)7 / 2 = 3.5
Object Casting (Upcasting and Downcasting)
public class ObjectCasting {
public static void main(String[] args) {
// UPCASTING: child → parent (always safe, implicit)
Dog dog = new Dog("Rex");
Animal animal = dog; // upcasting (automatic)
animal.eat(); // works
// animal.bark(); // ERROR: Animal doesn't know about bark()
// DOWNCASTING: parent → child (risky, explicit)
if (animal instanceof Dog) {
Dog sameDog = (Dog) animal; // downcasting (explicit)
sameDog.bark(); // works now!
}
// Pattern matching (Java 16+)
if (animal instanceof Dog d) {
d.bark(); // automatic casting!
}
// ClassCastException example
Animal genericAnimal = new Animal("Generic");
try {
Dog notADog = (Dog) genericAnimal; // RUNTIME ERROR!
} catch (ClassCastException e) {
System.out.println("Cannot cast: " + e.getMessage());
}
}
}
class Animal {
String name;
Animal(String name) { this.name = name; }
void eat() { System.out.println(name + " is eating"); }
}
class Dog extends Animal {
Dog(String name) { super(name); }
void bark() { System.out.println(name + " says: Woof!"); }
}Rex is eating Rex says: Woof! Rex says: Woof! Cannot cast: Animal cannot be cast to Dog
String Conversions
public class StringConversions {
public static void main(String[] args) {
// Primitive → String
int num = 42;
String s1 = String.valueOf(num); // preferred
String s2 = Integer.toString(num); // also works
String s3 = "" + num; // concatenation (less efficient)
System.out.println("int → String: " + s1);
// String → Primitive
String str = "123";
int i = Integer.parseInt(str);
double d = Double.parseDouble("3.14");
boolean b = Boolean.parseBoolean("true");
System.out.println("String → int: " + i);
System.out.println("String → double: " + d);
System.out.println("String → boolean: " + b);
// Invalid conversion throws exception
try {
int invalid = Integer.parseInt("hello");
} catch (NumberFormatException e) {
System.out.println("\nNumberFormatException: " + e.getMessage());
}
}
}int → String: 42 String → int: 123 String → double: 3.14 String → boolean: true NumberFormatException: For input string: "hello"
Common Mistakes
- Forgetting to cast in integer division —
int result = 5/2;gives 2, not 2.5. Cast one operand:(double)5/2. - Assuming narrowing preserves value —
(byte)130is NOT 130; it wraps around to -126. Always check ranges. - Casting objects without instanceof check — causes
ClassCastExceptionat runtime. Always check withinstanceoffirst. - Losing precision with long→float —
float f = 123456789L;may lose precision because float has only ~7 significant digits. Result: 1.23456792E8. - Mixing signed and unsigned arithmetic — Java has no unsigned types (except char). Large long values cast to int produce negative numbers.
Interview Questions
Q1: What is the difference between implicit and explicit casting?
Answer: Implicit (widening) casting happens automatically when converting to a larger type (byte→int, int→double). No data loss occurs. Explicit (narrowing) casting requires the programmer to write (targetType) and may lose data (double→int truncates decimals, int→byte can overflow).
Q2: Why does byte + byte produce an int in Java?
Answer: Java promotes byte, short, and char operands to int before performing arithmetic operations. This is called type promotion and exists to prevent overflow during intermediate calculations (byte can only hold -128 to 127, but byte+byte could be up to 254).
Q3: What is the difference between truncation and rounding?
Answer: Casting double to int uses truncation — it simply drops the decimal part without rounding. (int)9.99 is 9, not 10. For rounding, use Math.round() which returns the closest integer value.
Q4: Explain upcasting vs downcasting in Java.
Answer: Upcasting (child→parent) is always safe and implicit: Animal a = new Dog(). You lose access to child-specific methods. Downcasting (parent→child) is explicit and risky: Dog d = (Dog)animal. It can throw ClassCastException if the object isn't actually that type. Always check with instanceof before downcasting.
Q5: Can you cast between unrelated types?
Answer: No. You cannot cast between unrelated classes (e.g., String to Integer). The compiler rejects casts between types that have no inheritance relationship. You CAN cast between types in the same hierarchy (parent↔child), and you can always cast primitives following widening/narrowing rules.
Summary
Type casting in Java falls into two categories: widening (automatic, safe, smaller→larger) and narrowing (manual, risky, larger→smaller). Java's type promotion rules automatically widen operands in expressions. Object casting uses upcasting (implicit, safe) and downcasting (explicit, requires instanceof check). Understanding when data loss occurs and how to prevent it is essential for writing bug-free Java programs.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Type Casting in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, fundamentals, syntax, basics
Related Java Master Course Topics