Java Type Casting (Widening/Narrowing) & var Keyword
Widening Casting (Implicit) ยท Narrowing Casting (Explicit) ยท Data Loss & Overflow ยท ASCII char/int Conversions ยท var Keyword (Local Variable Type Inference)
Comprehensive masterclass on Java type conversion: widening automatic casting, narrowing explicit casting, truncation and overflow risks, character-to-integer Unicode conversions, and local variable type inference with the modern var keyword (Java 10+).
1. What is Type Casting in Java?
Type Casting is the process of converting a value of one primitive data type into another data type.
In Java, type casting is divided into two primary categories:
+-----------------------------------------------------------------------------------+
| JAVA TYPE CASTING HIERARCHY |
+-----------------------------------------------------------------------------------+
| 1. WIDENING CASTING (Implicit / Automatic - Safe, No Data Loss) |
| byte -> short -> char -> int -> long -> float -> double |
| (Smaller memory size converted automatically to larger memory container) |
+-----------------------------------------------------------------------------------+
| 2. NARROWING CASTING (Explicit / Manual - Dangerous, Potential Data Loss) |
| double -> float -> long -> int -> char -> short -> byte |
| (Larger memory size forced into smaller memory container with (type) syntax) |
+-----------------------------------------------------------------------------------+2. Widening Casting (Implicit / Automatic)
Widening casting happens automatically when passing a smaller data type to a larger data type container. Because the destination container has more bits than the source, no data loss occurs:
int smallNumber = 100;
double largeNumber = smallNumber; // Automatic Widening: int (4 bytes) -> double (8 bytes)
System.out.println(smallNumber); // 100
System.out.println(largeNumber); // 100.0
3. Narrowing Casting (Explicit / Manual) & Overflow Risks
Narrowing casting must be done manually by placing the target type in parentheses (targetType) before the value.
Because you are cramming a larger number of bits into a smaller memory container, precision loss (truncation of decimals) or arithmetic integer overflow can occur:
// Decimal Truncation:
double itemPrice = 99.95;
int truncatedPrice = (int) itemPrice; // Fractional decimals (.95) discarded! Evaluates to 99
// Byte Overflow (Wrap-around):
int largeInt = 130;
byte overflowByte = (byte) largeInt; // Max byte is 127! Wraps around to -126!
4. Char to Int & Int to Char (Unicode Code Points)
Because char is an unsigned 16-bit numeric type under the hood, you can freely cast between characters and their integer ASCII/Unicode values:
char letter = 'A';
int asciiValue = (int) letter; // Evaluates to 65
int charCode = 66;
char convertedChar = (char) charCode; // Evaluates to 'B'
5. Modern Java: Local Variable Type Inference with `var`
Starting in Java 10, Java introduced the var keyword for Local Variable Type Inference.
With var, the compiler automatically detects the variable's type from the right-hand initialization expression:
var age = 25; // Inferred as int
var price = 99.99; // Inferred as double
var greeting = "Hello, Java 21!"; // Inferred as String
var active = true; // Inferred as boolean
var usersList = new ArrayList<String>(); // Inferred as ArrayList<String>Crucial Rules for Using var:
1. Still Statically Typed: var does NOT make Java dynamically typed like Python/JavaScript. Once inferred, the type is fixed!
var count = 10;
// count = "ten"; // COMPILE ERROR: incompatible types!var can ONLY be used inside method bodies. It CANNOT be used for class fields, method parameters, or return types.
3. Mandatory Initialization: var x; is illegal because the compiler cannot infer an uninitialized variable.
Beginner Example & Code Anatomy
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// 1. Widening Casting (Implicit)
int salaryInt = 50000;
double salaryDouble = salaryInt; // int -> double
System.out.println("Widening Casting (int -> double): " + salaryDouble);
// 2. Narrowing Casting (Explicit Truncation)
double marketRate = 1845.75;
int roundedRate = (int) marketRate; // Discards .75
System.out.println("Narrowing Casting (double -> int): " + roundedRate + " (Decimals discarded)");
// 3. Char to ASCII conversion
char symbol = 'Z';
int asciiCode = (int) symbol;
System.out.println("Character '" + symbol + "' has ASCII code: " + asciiCode);
// 4. Local Variable Type Inference with 'var' (Java 10+)
var transactionId = 987654321L; // Inferred as long
var accountHolder = "Anita Desai"; // Inferred as String
var isVerified = true; // Inferred as boolean
System.out.println("
--- Modern Java 'var' Inferred Types ---");
System.out.println("Transaction ID : " + transactionId + " (Type: " + ((Object)transactionId).getClass().getSimpleName() + ")");
System.out.println("Account Holder : " + accountHolder + " (Type: " + accountHolder.getClass().getSimpleName() + ")");
System.out.println("Verified Status: " + isVerified);
}
}
๐ Line-by-Line Code Explanation
double salaryDouble = salaryInt;
Implicit widening casting: converts 32-bit integer 50000 into 64-bit float 50000.0 with zero precision loss.
int roundedRate = (int) marketRate;
Explicit narrowing cast: truncates decimal fraction .75, keeping integer portion 1845.
int asciiCode = (int) symbol;
Converts Unicode character 'Z' to its decimal integer code point (90).
var transactionId = 987654321L;
Java 10+ local variable type inference: compiler infers type as long at compile-time.
Practical Real-World Example
public class ByteOverflowInspector {
public static void main(String[] args) {
System.out.println("=== Demonstrating Byte Overflow in Narrowing Cast ===");
int originalValue = 130;
// Maximum byte value is 127
byte castedByte = (byte) originalValue;
System.out.println("Original int value : " + originalValue);
System.out.println("Casted byte value : " + castedByte + " (Binary wrap-around!)");
// Explanation of binary wrap-around
// 130 in binary (32-bit): 00000000 00000000 00000000 10000010
// Lower 8-bits: 10000010 (In Two's Complement signed byte, MSB 1 means negative: -126)
}
}
- Using var without immediate initialization: Writing "var x;" causes compile error: "cannot infer type for local variable x (cannot use 'var' on variable without initializer)".
- Using var as a class field: Writing "class User { var age = 20; }" is illegal. var is permitted only for local variables inside methods.
- Assuming cast rounds to nearest integer: (int) 9.99 results in 9, NOT 10! Narrowing casting truncates towards zero; it does not perform mathematical rounding. Use Math.round() for rounding.
Test your understanding by writing the code directly in your editor or running in our online Java compiler:
// Coding Challenge:
// Given a total bill of 1450.85:
// 1. Cast it to an int (rupeesOnly)
// 2. Extract the remaining paise as an integer (paiseOnly = (int) Math.round((bill - rupeesOnly) * 100))
// 3. Print: "โน1450 and 85 Paise"
public class Main {
public static void main(String[] args) {
double bill = 1450.85;
// TODO: Perform the casting operations and print formatted bill
}
}
๐ก Frequently Asked Questions & Interview Insights
โ Does using "var" slow down application runtime execution?
Not at all! "var" is resolved entirely at compile-time by javac. The generated .class Bytecode is 100% identical to explicit type declarations, resulting in zero runtime overhead.
โ What is the safe way to cast between Object types?
Always check with "instanceof" before casting objects to avoid runtime ClassCastException: "if (obj instanceof String str) { System.out.println(str.length()); }".
โ Why does integer division truncate decimals before casting?
In "double d = (double) (5 / 2);", the division (5 / 2) executes first as integer math (2), and then 2 is cast to 2.0. To preserve decimals, cast before dividing: "(double) 5 / 2" yields 2.5.
๐ Quick Chapter Recap
- Widening casting (smaller to larger) is automatic and safe from data loss.
- Narrowing casting (larger to smaller) requires explicit (type) syntax and truncates decimals or overflows.
- char and int can be converted based on Unicode numeric code points.
- var (Java 10+) provides local variable compile-time type inference without sacrificing static type safety.