Java Type Casting (Widening/Narrowing) & var Keyword

โ˜• Java 21+ LTS ๐ŸŸข Chapter 9 of 47 ๐Ÿ“‚ Phase 2: Variables & Data Types ๐Ÿ“… 2026 Edition
๐Ÿ“Œ Covered in this chapter:

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!
2. Local Variables Only: 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

โ˜• Main.java โ€” Chapter 9 Core Example
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);
    }
}
๐Ÿ’ป Program Console Output
Widening Casting (int -> double): 50000.0 Narrowing Casting (double -> int): 1845 (Decimals discarded) Character 'Z' has ASCII code: 90 --- Modern Java 'var' Inferred Types --- Transaction ID : 987654321 (Type: Long) Account Holder : Anita Desai (Type: String) Verified Status: true

๐Ÿ” 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

โ˜• PracticalApplication.java โ€” Industry Implementation
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)
    }
}
๐Ÿ’ป Practical Console Output
=== Demonstrating Byte Overflow in Narrowing Cast === Original int value : 130 Casted byte value : -126 (Binary wrap-around!)
โš ๏ธ Common Mistakes & Professional Best Practices
  • 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.
๐ŸŽฏ Hands-on Coding Challenge

Test your understanding by writing the code directly in your editor or running in our online Java compiler:

โ˜• Challenge.java
// 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.
โ† Prev: 8. Reference Types & Scopes Next: 10. Basic Operators โ†’
OC
Curated by Our Compiler Java Technical Editorial Team
Published for 2026 Academic & Enterprise Reference ยท 100% Free & Open Access