Type Conversions and Casts

Introduction

Type conversion is the process of converting a value from one data type to another. In Java, this is necessary when you want to assign a value of one type to a variable of another type.

Why Type Conversion?

  1. Compatibility: Make different types work together
  2. Precision: Convert between integer and decimal
  3. Operations: Perform operations on compatible types
  4. API Requirements: Match required parameter types

Types of Type Conversion

Java has two types of type conversion:

  1. Implicit Conversion (Automatic/Widening)
  2. Explicit Conversion (Manual/Narrowing/Casting)

1. Implicit Type Conversion (Widening)

Definition: Automatic conversion from smaller to larger data type by the Java compiler.

Conversion Hierarchy:

byte → short → int → long → float → double

        char

Characteristics:

  • Automatic: Done by compiler
  • Safe: No data loss
  • Smaller to Larger: Lower capacity to higher capacity
  • No casting needed: Happens automatically

Examples:

// byte to int
byte b = 10;
int i = b;  // Automatic conversion
System.out.println(i);  // 10

// int to long
int num = 100;
long bigNum = num;  // Automatic
System.out.println(bigNum);  // 100

// int to float
int x = 50;
float f = x;  // Automatic
System.out.println(f);  // 50.0

// int to double
int value = 25;
double d = value;  // Automatic
System.out.println(d);  // 25.0

// char to int
char c = 'A';
int ascii = c;  // Automatic
System.out.println(ascii);  // 65

// float to double
float f1 = 10.5f;
double d1 = f1;  // Automatic
System.out.println(d1);  // 10.5

Complete Chain Example:

byte b = 10;
short s = b;     // byte → short
int i = s;       // short → int
long l = i;      // int → long
float f = l;     // long → float
double d = f;    // float → double

System.out.println("byte: " + b);      // 10
System.out.println("short: " + s);    // 10
System.out.println("int: " + i);      // 10
System.out.println("long: " + l);     // 10
System.out.println("float: " + f);    // 10.0
System.out.println("double: " + d);   // 10.0

In Expressions:

byte b = 10;
int i = 20;

// byte is automatically promoted to int
int result = b + i;  // 30

float f = 5.5f;
double d = 10.5;

// float is automatically promoted to double
double result2 = f + d;  // 16.0

2. Explicit Type Conversion (Narrowing/Casting)

Definition: Manual conversion from larger to smaller data type using cast operator.

Conversion Hierarchy (Reverse):

double → float → long → int → short → byte

                 char

Characteristics:

  • Manual: Must be done by programmer
  • Risky: Possible data loss
  • Larger to Smaller: Higher capacity to lower capacity
  • Casting required: Use (type) syntax

Syntax:

targetType variable = (targetType) value;

Examples:

1. double to int:

double d = 10.99;
int i = (int) d;  // Explicit cast required
System.out.println(i);  // 10 (decimal part lost)

// Without cast - ERROR
int i = d;  // ✗ Error: incompatible types

2. long to int:

long l = 100000L;
int i = (int) l;  // Explicit cast
System.out.println(i);  // 100000

// Data loss example
long big = 2147483648L;  // Greater than int max
int i = (int) big;       // Data loss
System.out.println(i);   // -2147483648 (overflow)

3. float to int:

float f = 15.75f;
int i = (int) f;  // Explicit cast
System.out.println(i);  // 15 (decimal lost)

4. int to byte:

int i = 100;
byte b = (byte) i;  // Explicit cast
System.out.println(b);  // 100

// Out of range - data loss
int large = 200;  // byte range: -128 to 127
byte b2 = (byte) large;
System.out.println(b2);  // -56 (overflow)

5. int to char:

int ascii = 65;
char c = (char) ascii;  // Explicit cast
System.out.println(c);  // 'A'

int num = 97;
char ch = (char) num;
System.out.println(ch);  // 'a'

6. double to float:

double d = 10.5;
float f = (float) d;  // Explicit cast
System.out.println(f);  // 10.5

Data Loss Examples:

// Decimal part lost
double d = 99.99;
int i = (int) d;
System.out.println(i);  // 99

// Precision lost
float f = 123.456789f;
System.out.println(f);  // 123.45679 (some precision lost)

// Overflow
int big = 130;
byte b = (byte) big;  // 130 > 127 (max byte)
System.out.println(b);  // -126 (overflow wraps around)

Type Promotion in Expressions

When different types are used in an expression, Java automatically promotes them to a common type.

Rules:

  1. All byte, short, and char are promoted to int
  2. If any operand is long, all are promoted to long
  3. If any operand is float, all are promoted to float
  4. If any operand is double, all are promoted to double

Examples:

// byte promoted to int
byte b1 = 10;
byte b2 = 20;
// byte result = b1 + b2;  // ✗ Error: result is int
int result = b1 + b2;       // ✓ Correct
System.out.println(result);  // 30

// char promoted to int
char c1 = 'A';  // 65
char c2 = 'B';  // 66
int sum = c1 + c2;  // Both promoted to int
System.out.println(sum);  // 131

// Mixed types
int i = 10;
float f = 5.5f;
float result2 = i + f;  // int promoted to float
System.out.println(result2);  // 15.5

// byte, int, float
byte b = 5;
int x = 10;
float y = 2.5f;
float result3 = b + x + y;  // All promoted to float
System.out.println(result3);  // 17.5

Special Case - byte/short/char:

byte a = 10;
byte b = 20;

// This doesn't work
// byte c = a + b;  // ✗ Error: a+b is int

// Must cast back
byte c = (byte)(a + b);  // ✓ Correct
System.out.println(c);  // 30

String Conversions

1. Primitive to String:

Using String Concatenation:

int num = 10;
String str = "" + num;  // "10"
System.out.println(str);

double d = 10.5;
String str2 = "" + d;  // "10.5"

Using String.valueOf():

int num = 100;
String str = String.valueOf(num);  // "100"

double d = 99.99;
String str2 = String.valueOf(d);  // "99.99"

boolean flag = true;
String str3 = String.valueOf(flag);  // "true"

Using toString() (Wrapper Classes):

int num = 50;
String str = Integer.toString(num);  // "50"

double d = 25.5;
String str2 = Double.toString(d);  // "25.5"

2. String to Primitive:

Using Wrapper Classes:

// String to int
String str = "123";
int num = Integer.parseInt(str);
System.out.println(num);  // 123

// String to double
String str2 = "99.99";
double d = Double.parseDouble(str2);
System.out.println(d);  // 99.99

// String to long
String str3 = "1000000";
long l = Long.parseLong(str3);
System.out.println(l);  // 1000000

// String to boolean
String str4 = "true";
boolean flag = Boolean.parseBoolean(str4);
System.out.println(flag);  // true

// String to float
String str5 = "10.5";
float f = Float.parseFloat(str5);
System.out.println(f);  // 10.5

Error Handling:

String str = "abc";
try {
    int num = Integer.parseInt(str);  // Throws exception
} catch (NumberFormatException e) {
    System.out.println("Invalid number format");
}

Object Type Casting

Upcasting (Automatic):

// Parent reference, child object
Object obj = "Hello";  // String is child of Object
Number num = 10;       // Integer is child of Number

Downcasting (Explicit):

Object obj = "Hello";
String str = (String) obj;  // Explicit cast
System.out.println(str);  // "Hello"

// Check before casting
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s);
}

Common Mistakes and Errors

1. Implicit Narrowing:

int i = 100;
byte b = i;  // ✗ Error: incompatible types
byte b = (byte) i;  // ✓ Correct

2. Decimal Loss:

double d = 10.99;
int i = (int) d;  // i = 10 (lost .99)

3. Overflow:

int big = 200;
byte b = (byte) big;  // b = -56 (overflow)

4. String Parsing:

String str = "abc";
int num = Integer.parseInt(str);  // ✗ NumberFormatException

5. Division Result:

int a = 5, b = 2;
double result = a / b;  // 2.0 (not 2.5!)

// Correct ways:
double result = (double) a / b;  // 2.5 ✓
double result = a / (double) b;  // 2.5 ✓
double result = 1.0 * a / b;     // 2.5 ✓

Best Practices

  1. Prefer Implicit: Use implicit conversion when possible
  2. Check Range: Ensure value fits in target type
  3. Use instanceof: Before downcasting objects
  4. Handle Exceptions: When parsing strings
  5. Document Casts: Comment why casting is needed
  6. Avoid Unnecessary Casts: Don’t cast if not needed
// Bad - unnecessary cast
int i = 10;
long l = (long) i;  // Cast not needed (implicit works)

// Good
int i = 10;
long l = i;  // Implicit conversion

Conversion Methods Summary

Primitive to String:

String.valueOf(value)
Integer.toString(value)
"" + value

String to Primitive:

Integer.parseInt(str)
Double.parseDouble(str)
Long.parseLong(str)
Boolean.parseBoolean(str)
Float.parseFloat(str)

Number Conversions:

int i = (int) doubleValue;
long l = (long) intValue;
float f = (float) doubleValue;
double d = floatValue;  // Automatic

Exam Tips

Remember:

  1. Widening (Implicit):

    • Automatic, safe, no data loss
    • Smaller → Larger
    • byte → short → int → long → float → double
  2. Narrowing (Explicit):

    • Manual, risky, possible data loss
    • Larger → Smaller
    • Requires cast: (type)
  3. Type Promotion:

    • byte, short, char → int in expressions
    • Result promoted to largest type in expression
  4. String Conversions:

    • To String: String.valueOf(), toString(), + ""
    • From String: parseInt(), parseDouble(), etc.
  5. Casting Syntax: (targetType) value

  6. Data Loss:

    • Decimal part lost: double → int
    • Overflow: int → byte (if out of range)
    • Precision lost: double → float

Common Questions:

  1. What is type conversion?
  2. Difference between implicit and explicit conversion
  3. What is type promotion in expressions?
  4. How to convert String to int?
  5. Why is casting needed?
  6. What happens when int is cast to byte?
  7. Explain widening and narrowing
  8. What is data loss in type conversion?