Type Casting

Reviewed & published by Brayan K

Sooner or later you'll have an int where you need a double, or a double where you need an int. Type casting is how you convert between them — sometimes safely and automatically, sometimes manually and at your own risk.

Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Widening — The Safe, Automatic Direction

Going from a smaller type to a larger one is called widening. Because the bigger type can hold every value the smaller one could, no data is ever lost — so Java performs it automatically with no special syntax.

byte  → short → int → long → float → double
        ───────── widening (automatic) ─────────►

💡 Analogy: Widening is pouring a small cup of water into a big bucket — everything fits, nothing spills. Java is happy to do it for you.

public class Main {
    public static void main(String[] args) {
        // WIDENING: small type -> big type. Java does it AUTOMATICALLY.
        // No data can be lost, so no cast syntax is required.
        byte  b = 42;
        int   i = b;        // byte  -> int    (automatic)
        long  l = i;        // int   -> long   (automatic)
        double d = l;       // long  -> double (automatic)

        System.out.println("byte   b = " + b);
        System.out.println("int    i = " + i);
        System.out.println("long   l = " + l);
        System.out.println("double d = " + d);   // note the .0

        // A char widens to int as its Unicode value
        char grade = 'A';
        int code = grade;   // 'A' -> 65
        System.out.println("'A' widened to int = " + code);

        // Mixed arithmetic auto-promotes to the widest type involved
        int   count = 3;
        double price = 2.50;
        double total = count * price;  // int promoted to double
        System.out.println("3 * 2.50 = " + total);
    }
}

2️⃣ Narrowing — The Risky, Manual Direction

Going from a larger type to a smaller one is narrowing. Data can be lost, so Java refuses to do it silently. You must write an explicit cast: (targetType) value.

double price = 19.99;
int dollars = (int) price;   // explicit cast required -> 19
//             ↑ this says "yes, I know I'm dropping the .99"

💡 Analogy: Narrowing is pouring a full bucket into a small cup. Whatever doesn't fit overflows onto the floor and is gone forever.

public class Main {
    public static void main(String[] args) {
        // NARROWING: big type -> small type. You must cast EXPLICITLY,
        // and you may lose data. Java forces you to say "I accept the risk".
        double pi = 3.99;
        int truncated = (int) pi;     // drops the fraction -> 3 (NOT rounded!)
        System.out.println("(int) 3.99 = " + truncated);

        // Overflow during narrowing wraps silently
        int big = 300;
        byte small = (byte) big;      // 300 doesn't fit in a byte (-128..127)
        System.out.println("(byte) 300 = " + small);   // 44, wrapped

        // To ROUND instead of truncate, use Math.round (returns long)
        double score = 86.7;
        long rounded = Math.round(score);
        System.out.println("Math.round(86.7) = " + rounded);

        // Cast back down to int after rounding
        int finalScore = (int) Math.round(score);
        System.out.println("rounded int = " + finalScore);
    }
}

3️⃣ Truncate vs Round

Beginners constantly confuse these. Pick the tool that matches your intent:

GoalCode86.7 →
Chop off decimals(int) x86
Round to nearestMath.round(x)87
Round up alwaysMath.ceil(x)87.0
Round down alwaysMath.floor(x)86.0

Math.ceil and Math.floor return a double; Math.round returns a long. Cast to int if that's what you need.

4️⃣ Casting Is Not Parsing

This is the single biggest source of confusion. Casting converts between numeric types. Parsing turns a String of digits into a number. They are completely different operations.

int x = (int) "25";              // ❌ compile error! text is not a number
int y = Integer.parseInt("25");  // ✅ parses text -> 25
double z = Double.parseDouble("19.99"); // ✅ -> 19.99

Going the other way (number → text) is easy: concatenate with "" or call String.valueOf.

public class Main {
    public static void main(String[] args) {
        // Casting only works between NUMERIC types. To turn TEXT into a
        // number you must PARSE it (a different operation entirely).
        String ageText = "25";
        int age = Integer.parseInt(ageText);
        System.out.println("Parsed age + 1 = " + (age + 1));

        String priceText = "19.99";
        double price = Double.parseDouble(priceText);
        System.out.printf("Parsed price * 2 = %.2f%n", price * 2);

        // Number -> String: just concatenate, or use String.valueOf
        int score = 95;
        String label = "Score: " + score;       // implicit toString
        String asText = String.valueOf(score);   // explicit
        System.out.println(label);
        System.out.println("length of \"" + asText + "\" = " + asText.length());

        // A common bug: "5" + 3 is "53", not 8!
        System.out.println("\"5\" + 3 = " + ("5" + 3));
        System.out.println("5 + 3   = " + (5 + 3));
    }
}
public class Main {
    public static void main(String[] args) {
        // 🎯 YOUR TURN — replace each ___ using the hint beside it.

        int totalPence = 1275;

        // 1) int / int is integer division: the pennies are thrown away.
        int whole = totalPence / 100;
        System.out.println("Whole pounds: " + whole);

        // 2) Make one side a double FIRST and the division keeps the decimals.
        double pounds = (___) totalPence / 100;   // 👉 replace ___ with double
        System.out.println("Exact pounds: " + pounds);

        double perItem = 9.99;

        // 3) Casting to int chops the decimals off. It does not round.
        int rounded = (___) perItem;              // 👉 replace ___ with int
        System.out.println("Cast truncates: " + rounded);

        // 4) When you DO want rounding, ask for it by name.
        System.out.println("Math.round gives: " + Math.___(perItem));  // 👉 replace ___ with round

        // Narrowing a long that does not fit wraps around silently.
        long big = 3000000000L;
        int narrowed = (int) big;
        System.out.println("Narrowed long: " + narrowed);

        // 5) Text is not a number until you parse it — a cast will not do.
        String typed = "42";
        int parsed = Integer.___(typed);          // 👉 replace ___ with parseInt
        System.out.println("Parsed + 1 = " + (parsed + 1));

        char letter = 'A';
        int code = letter;   // widening: a char IS a small number
        System.out.println("'A' as an int: " + code);
    }
}

🧩 Reorder Challenge

Unscramble these lines so the program reads the text "7.5", multiplies by 3, and prints the whole-number part.

int whole = (int) result;
double result = hours * 3;
System.out.println("Whole hours: " + whole);
double hours = Double.parseDouble("7.5");
System.out.println("Exact: " + result);
double hours = Double.parseDouble("7.5");
double result = hours * 3;
System.out.println("Exact: " + result);
int whole = (int) result;
System.out.println("Whole hours: " + whole);

Why: You must parse the text into hours before using it. result depends on hours, so it comes next (22.5). Then the cast (int) result truncates 22.5 to 22, which prints last. Each variable must be declared before it is referenced.

🧠 Quick Recall

1. What does this print?

System.out.println((int) 9.99);

9. The cast truncates toward zero — it does not round to 10.

2. What does this print?

int a = 5;
double b = a / 2;
System.out.println(b);

2.0. a / 2 is int-by-int division giving 2; only then is the 2 widened to 2.0. To get 2.5 you'd write a / 2.0.

3. What does this print?

System.out.println(Integer.parseInt("12") + 8);

20. Parsing turns "12" into the int 12, so this is real arithmetic, not concatenation.

Common Beginner Mistakes

📋 Quick Reference

CodeDescriptionExample → result
int i = aByte;Widening — automatic, no castbyte → int → long → double
(int) xNarrowing — truncates toward zero(int) 3.99 → 3
(int) xTruncation drops sign-side too(int) -3.99 → -3
(byte) xOut-of-range narrowing wraps(byte) 300 → 44
Math.round(x)Round to nearest (returns long)Math.round(86.7) → 87
(int) Math.round(x)Rounded value as an int(int) Math.round(86.7) → 87
(char) iint → char (Unicode code point)(char) 65 → 'A'
Integer.parseInt(s)Parse text → intparseInt("25") → 25
Double.parseDouble(s)Parse text → doubleparseDouble("19.99") → 19.99
Long.parseLong(s)Parse text → longparseLong("100") → 100
String.valueOf(x)Number → String (explicit)String.valueOf(95) → "95"
"" + xNumber → String (concatenation)"" + 95 → "95"
"5" + 3+ with a String means concatenation→ "53", not 8
(double) 5 / 2Cast one operand to avoid int division→ 2.5 (5 / 2 → 2)

🎉 Lesson Complete!

You can now convert between Java's numeric types with confidence: widening is automatic, narrowing needs an explicit (type) cast, casting truncates while Math.round rounds, and turning text into numbers is parsing, not casting.

Practice quiz

What does (int) 3.99 evaluate to?

  • 4
  • 3.99
  • 3
  • 0

Answer: 3. Casting a double to int truncates toward zero - it does NOT round - so the .99 is discarded, giving 3.

Why is widening automatic but narrowing requires an explicit cast?

  • Widening can never lose data; narrowing can, so Java forces you to signal you accept the loss
  • Widening is slower
  • Narrowing is impossible in Java
  • Both require a cast

Answer: Widening can never lose data; narrowing can, so Java forces you to signal you accept the loss. A bigger type holds every value the smaller one could, so widening is safe and silent. Narrowing can drop data, so an explicit (type) cast is required.

What does (byte) 300 produce?

  • 300
  • 127
  • It throws an exception
  • 44

Answer: 44. 300 doesn't fit in a byte (-128..127), so it wraps silently using the low 8 bits, giving 44.

What does this print? int a = 5; double b = a / 2; System.out.println(b);

  • 2.5
  • 2.0
  • 2
  • 3.0

Answer: 2.0. a / 2 is int-by-int division giving 2; only then is it widened to 2.0. To get 2.5 use a / 2.0.

What is the difference between casting and parsing?

  • Casting converts between numeric types; parsing turns a String of digits into a number
  • They are the same operation
  • Parsing only works on doubles
  • Casting works on Strings too

Answer: Casting converts between numeric types; parsing turns a String of digits into a number. Casting uses (type) between numeric types. Parsing uses Integer.parseInt / Double.parseDouble to turn text into a number. (int)"25" is a compile error.

What does "5" + 3 evaluate to?

  • 8
  • "8"
  • "53"
  • 53 as an int

Answer: "53". The + operator means string concatenation when either side is a String, so 3 becomes "3" and is joined, giving "53".

What does Math.round(86.7) return, and what is its type?

  • 86 as an int
  • 87 as a long
  • 86.7 as a double
  • 87 as an int

Answer: 87 as a long. Math.round rounds to the nearest whole number (87) and returns a long. Cast to int if you need an int.

What does Integer.parseInt("12") + 8 evaluate to?

  • "128"
  • "20"
  • 128
  • 20

Answer: 20. parseInt turns "12" into the int 12, so this is real arithmetic: 12 + 8 = 20, not concatenation.

What does (double) 5 / 2 evaluate to?

  • 2
  • 2.5
  • 2.0
  • 3.0

Answer: 2.5. The cast applies to 5 first, making it 5.0, so 5.0 / 2 is double division giving 2.5.

What does (char) 65 produce?

  • '6'
  • 65
  • 'A'
  • 'a'

Answer: 'A'. Casting int 65 to char gives the Unicode/ASCII character at code point 65, which is 'A'.

Continue this course

Frequently asked questions

What is the difference between casting and parsing?

Casting converts between compatible NUMERIC types — int to double, double to int, long to byte — using the (type) syntax. Parsing converts a String of digits into a number using Integer.parseInt or Double.parseDouble. You cannot cast "25" to an int with (int)"25"; text is not a number to Java, so it must be parsed.

Why is widening automatic but narrowing requires a cast?

Widening (int to double, byte to int) can never lose information because the bigger type holds every value the smaller one could, so Java does it silently. Narrowing (double to int, int to byte) can lose data — the fraction or high bits are discarded — so Java forces you to write an explicit (type) cast as a signal that you understand and accept the loss.

Does casting a double to an int round it?

No. (int) 3.99 gives 3, not 4 — it simply truncates toward zero, throwing away everything after the decimal point. (int) -3.99 gives -3. If you want proper rounding, use Math.round (which returns a long) and then cast that to int: (int) Math.round(3.99).

What happens if I narrow a value that doesn't fit?

It wraps around using the target type's bit pattern, with no error. (byte) 300 is 44 because only the low 8 bits survive. This is the same silent overflow behaviour as arithmetic. If a value might not fit, validate the range first or keep the wider type.

Why does "5" + 3 give "53" instead of 8?

The + operator means string concatenation whenever either side is a String. Since "5" is text, 3 is converted to "3" and joined, giving "53". To do arithmetic you must first parse the text: Integer.parseInt("5") + 3 gives 8.