Type casting in Java is the process of converting one data type to another. Sometimes Java does this automatically, and sometimes you need to tell Java explicitly how to convert one thing to another.
In many case though, Java does not allow you to convert between types. You cannot cast from a House to a Person, for example.
Understanding casting is important because different data types have different ranges and precision, and you need to know how to safely move data between them.
Java automatically converts smaller data types to larger ones when it’s safe to do so. This is called widening conversion or implicit casting.
public class ZipCode {
void compute() {
byte byteValue = 42;
short shortValue = byteValue; // byte -> short (automatic)
int intValue = shortValue; // short -> int (automatic)
long longValue = intValue; // int -> long (automatic)
float floatValue = longValue; // long -> float (automatic)
double doubleValue = floatValue; // float -> double (automatic)
System.out.println("Original byte: " + byteValue);
System.out.println("As double: " + doubleValue);
}
public static void main(String[] args) { new ZipCode().compute(); }
}What do I mean by "widening"?
When you convert from a smaller type to a larger type, you are "widening" the range of possible values.
For example, a byte can hold values from -128 to 127, while an int can hold values from -2,147,483,648 to 2,147,483,647.
When you convert a byte to an int, you are widening the range of possible values.
This is safe because every value that a byte can hold can also be represented as an int.
Java will automatically convert in this direction:
byte > short > int > long > float > double
char > int
public class ZipCode {
void compute() {
int wholeNumber = 100;
double decimalNumber = wholeNumber; // int automatically becomes double
System.out.println("Integer: " + wholeNumber); // 100
System.out.println("As double: " + decimalNumber); // 100.0
char letter = 'A';
int letterCode = letter; // char automatically becomes int (ASCII value)
System.out.println("Letter: " + letter); // A
System.out.println("ASCII code: " + letterCode); // 65
}
public static void main(String[] args) { new ZipCode().compute(); }
}When converting from a larger type to a smaller type, you must explicitly cast. This is called narrowing conversion or explicit casting.
And in many cases, this may not be safe, because you can lose data or precision.
For example, converting a double to an int will drop the decimal part.
Or converting a long to an int may cause overflow if the long value is too large to fit in an int.
You cannot put an int like 1000000 into a byte, because a byte can only hold values from -128 to 127.
(And it has to do with the number of bits used to store the value. A byte is 8 bits, and int is 32 bits.)
public class ZipCode {
void compute() {
double largeNumber = 123.789;
int wholeNumber = (int) largeNumber; // Explicit cast: double to int
System.out.println("Original double: " + largeNumber); // 123.789
System.out.println("Cast to int: " + wholeNumber); // 123 (decimal part lost!)
long bigNumber = 1000L;
int smallerNumber = (int) bigNumber; // Explicit cast: long to int
System.out.println("Long: " + bigNumber); // 1000
System.out.println("As int: " + smallerNumber); // 1000
}
public static void main(String[] args) { new ZipCode().compute(); }
}public class ZipCode {
void compute() {
// Casting can lose data!
double price = 19.99;
int dollars = (int) price; // Loses the cents!
System.out.println("Price: $" + price); // 19.99
System.out.println("Dollars: $" + dollars); // 19
// Casting very large numbers can cause overflow
long bigNumber = 3000000000L; // 3 billion
int overflowNumber = (int) bigNumber;
System.out.println("Long: " + bigNumber); // 3000000000
System.out.println("Cast to int: " + overflowNumber); // Negative number! (overflow)
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();It’s weird, but when you cast a long that is too big to fit in an int, you get a negative number. This is because of how numbers are stored in binary using two’s complement representation. (which is a whole other topic! and one you don’t need to know for now!)
Just file it away in your brain, that if you cast a number that is too big to fit in the smaller type, you get a weird negative number.
public class ZipCode {
void compute() {
// Number to character
int letterCode = 65;
char letter = (char) letterCode;
System.out.println("ASCII 65 is: " + letter); // A
// Character to number
char grade = 'B';
int gradeValue = (int) grade;
System.out.println("Letter " + grade + " has ASCII value: " + gradeValue); // 66
// Working with character arithmetic
char startLetter = 'A';
for (int i = 0; i < 5; i++) {
char currentLetter = (char) (startLetter + i);
System.out.print(currentLetter + " "); // A B C D E
}
System.out.println();
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();Converting between strings and numbers is very common:
public class ZipCode {
void compute() {
int age = 25;
double price = 19.99;
boolean isStudent = true;
// Convert to strings
String ageString = String.valueOf(age);
String priceString = String.valueOf(price);
String studentString = String.valueOf(isStudent);
System.out.println("Age as string: '" + ageString + "'");
System.out.println("Price as string: '" + priceString + "'");
System.out.println("Student status: '" + studentString + "'");
// Alternative: concatenation with empty string
String ageString2 = age + "";
String priceString2 = price + "";
System.out.println("Age (method 2): '" + ageString2 + "'");
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();Converting numbers to strings is straightforward using String.valueOf().
You can also concatenate a number with an empty string ("") to achieve the same effect.
public class ZipCode {
void compute() {
String ageText = "25";
String priceText = "19.99";
String heightText = "5.8";
// Convert strings to numbers
int age = Integer.parseInt(ageText);
double price = Double.parseDouble(priceText);
float height = Float.parseFloat(heightText);
System.out.println("Age: " + age);
System.out.println("Price: " + price);
System.out.println("Height: " + height);
// You can now do math with these!
int ageNextYear = age + 1;
double priceWithTax = price * 1.08;
System.out.println("Age next year: " + ageNextYear);
System.out.println("Price with tax: " + priceWithTax);
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();This example demonstrates how to convert text (strings) into numbers so you can perform mathematical operations. In the compute() method, three variables ageText, priceText, and heightText are defined as strings that look like numbers. To use these values in calculations, you need to change (or "cast") them into actual number types.
The code uses special methods for this conversion: Integer.parseInt() turns the string "25" into the integer 25, Double.parseDouble() converts "19.99" into the double 19.99, and Float.parseFloat() changes "5.8" into the float 5.8. After converting, the program prints out each value to show the result.
Once the values are numbers, you can do math with them. For example, it calculates ageNextYear by adding 1 to the age, and priceWithTax by multiplying the price by 1.08 (to add 8% tax). These results are printed as well.
The main method is the entry point of the program. It creates a new ZipCode object and calls the compute() method to run all the code above. This example is useful because it shows how to take user input (often as text) and turn it into numbers for calculations.
public class ZipCode {
void compute() {
String invalidNumber = "not-a-number";
try {
int number = Integer.parseInt(invalidNumber);
System.out.println("Number: " + number);
} catch (NumberFormatException e) {
System.out.println("Error: '" + invalidNumber + "' is not a valid number!");
}
// Safe conversion with default value
String userInput = "abc123";
int value = parseIntSafely(userInput, 0); // 0 is default if parsing fails
System.out.println("Parsed value: " + value);
}
public static int parseIntSafely(String text, int defaultValue) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();and the output would be
Error: 'not-a-number' is not a valid number! Parsed value: 0
This example shows how to handle cases where a string might not be a valid number. When you try to convert a string that doesn’t represent a number (like "not-a-number") using Integer.parseInt(), it throws a NumberFormatException. The code catches this exception and prints an error message instead of crashing. It also includes a helper method parseIntSafely() that attempts to parse a string into an integer and returns a default value if parsing fails. This is useful for safely handling user input that may not always be valid.
import java.util.Scanner;
public class ZipCode {
void compute() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter temperature in Fahrenheit: ");
String input = scanner.nextLine();
try {
double fahrenheit = Double.parseDouble(input);
double celsius = (fahrenheit - 32) * 5.0 / 9.0;
// Round to 1 decimal place
celsius = Math.round(celsius * 10.0) / 10.0;
System.out.println(fahrenheit + "°F = " + celsius + "°C");
// Cast to int for whole degrees
int wholeCelsius = (int) celsius;
System.out.println("Rounded down: " + wholeCelsius + "°C");
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number!");
}
scanner.close();
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();This example is a simple temperature converter that reads a temperature in Fahrenheit from the user, converts it to Celsius, and demonstrates both parsing a string to a number and casting a double to an int.
When you mix different numeric types in expressions, Java applies promotion rules:
public class ZipCode {
void compute() {
byte a = 10;
byte b = 20;
// This won't compile! byte + byte = int
// byte result = a + b; // ERROR!
// You need to cast back to byte
byte result = (byte) (a + b);
System.out.println("Result: " + result);
// Mixing types in expressions
int wholeNumber = 10;
double decimal = 3.5;
double mixedResult = wholeNumber + decimal; // int promoted to double
System.out.println("Mixed result: " + mixedResult); // 13.5
// Integer division vs. decimal division
int x = 7;
int y = 3;
System.out.println("Integer division: " + x / y); // 2
System.out.println("Decimal division: " + (double) x / y); // 2.333...
}
public static void main(String[] args) { new ZipCode().compute(); }
}
// now run it is jshell by
new ZipCode().compute();When you perform arithmetic operations, Java promotes smaller types to larger types to avoid data loss. For example, when adding two byte values, they are promoted to int before the addition. If you want to store the result back in a byte, you need to cast it explicitly.
When mixing different numeric types (like int and double), Java promotes the smaller type to the larger type. In the example, adding an int and a double results in a double.
The example also highlights the difference between integer division (which truncates the decimal part) and decimal division (which retains it). By casting one of the integers to double, you ensure that the division is performed in floating-point arithmetic.
-
Be careful with narrowing casts - You can lose data
-
Check ranges before casting to smaller types
-
Use appropriate parsing methods for strings
-
Handle exceptions when parsing user input
-
Be explicit about your intentions with casting
-
Understand precision loss when casting floats/doubles to integers
But wait, what is parsing ? Parsing user input means converting text (like what a user types) into a specific data type your program can use, such as turning the string "123" into the integer 123. This lets your code work with numbers, dates, or other types instead of just plain text.
And while most of the time Java is pretty salty about changing the type of things, there are some common situations where casting is okay, and very possibly, essential.
public class CastingAbout {
void compute() {
double value = 4.7;
// Truncation (casting just chops off decimal)
int truncated = (int) value;
System.out.println("Truncated: " + truncated); // 4
// Proper rounding
int rounded = (int) Math.round(value);
System.out.println("Rounded: " + rounded); // 5
// Rounding with more control
double price = 19.999;
int dollars = (int) (price + 0.5); // Add 0.5 then truncate
System.out.println("Price rounded: $" + dollars); // $20
}
public static void main(String[] args) { new CastingAbout().compute(); }
}
// now run it is jshell by
new CastingAbout().compute();When you cast a floating-point number (like double or float) to an integer type (like int), Java simply truncates the decimal part, effectively rounding down towards zero. This means that both positive and negative numbers lose their fractional component without rounding.
If you want to round a number to the nearest integer instead of just truncating it, you can use the Math.round() method. This method rounds to the nearest whole number, rounding up for .5 and above, and down for below .5.
Sometimes, BEFORE you make a cast from one type to another, you need to check that the number will fit. Well, perhaps you have a really big number, say something in the trillions. A number like is probably not fit in a java Integer. So you compare the number against the smallest and largest integers, and if it in or out of that range, you do or do not make the cast.
public class WonkyCast {
void compute() {
long bigNumber = 50000L;
long numberTrillion = 1_000_000_000_001L; // 1 trillion and 1.
// Check if it fits in an int before casting
if (bigNumber >= Integer.MIN_VALUE && bigNumber <= Integer.MAX_VALUE) {
int safeInt = (int) bigNumber;
System.out.println("Safe conversion: " + safeInt);
} else {
System.out.println("Number too large for int!");
}
// Check if it fits in an int before casting
if (numberTrillion >= Integer.MIN_VALUE && numberTrillion <= Integer.MAX_VALUE) {
int safeInt = (int) numberTrillion;
System.out.println("Safe conversion: " + numberTrillion);
} else {
System.out.println("Number"+ numberTrillion + " too large for int!");
}
}
public static void main(String[] args) { new WonkyCast().compute(); }
}
// now run it is jshell by
new WonkyCast().compute();when I run this, I’d get output of:
Safe conversion: 50000
Number 1000000000001 too large for int!Type casting is a fundamental skill in Java programming. Understanding when conversions happen automatically and when you need to be explicit will help you write more reliable and predictable code!
Type casting is the process of converting a variable from one data type to another. Java supports both automatic (widening) and explicit (narrowing) type casting. Widening conversions happen automatically when converting from a smaller to a larger type. Narrowing conversions require explicit casting and can lead to data loss or overflow. Be cautious when casting between incompatible types, and always validate user input when parsing strings to numbers.