Problem category: Compile-Time Problem
Diagnosis Difficulty: Easy
Difficulty to Fix: Easy
This problem usually occurs when you're trying to perform calculations using floating point numbers and then storing the results into an integer data type. Java has no problem promoting the data type of a value implicitly, however the designers decided that because an implicit demotion/down cast is likely an accident, the programmer must explicitly specify that's what they want.
The promotion diagram for Java data types looks like (follow the arrows for implicit promotions/casts):
` byte v short v int v long v float v double v boolean > String < Object < Polymorphic object ^ char
So for example, a byte can be implicitly cast to a short, but a short cannot be implicitly cast to a byte. The most common problems for beginners is dealing with casting of primitive types (particularly between floating point data types and integer data types).
Examples of some bad casts:
// simple examples // 1 int a = 5.5; // casting from double to int // 2 long b = 1; int c = b; // casting from long to int // 3 double d = 3; int e = d; // casting from double to int // more complex/subtle examples // 4 double f = 5; int g = 1 + 3 * b; // casting from double to int // 5 short h = 3; // casting from int to short // 6 float i = 3.5; // casting from double to float byte
Suggested fixes
For most cases (especially those involving number data types) you can usually specify an explicit cast. This is done by placing the type name in parenthesis, then an expression you want casted after that.
int a = (int) 5.5; // 5.5 is explicitly cast into an int, a=5
Note that when dealing with polymorphic objects and casting them down the inheritance chain will still perform type checking. For example:
public class Base {} public class Derive1 extends Base {} public class Derive2 extends Base {} //... Base a = new Derive1(); Derive2 b = (Derive1) a; // technically should compile, however on runtime you'll get a ClassCastException. You'll probably even get a warning saying this is an unsafe cast.
In the above example, the compiler cannot determine if a is a Derive1 object, a Derive2 object, or something else entirely.
Additionally, sometimes a cast demotion does not exist, even though a promotion cast does exist (for example a String to an int).
int a = (int) "5"; // invalid, there's no cast for a String to an int, implicit or explicit
In these cases, you have 2 options:
1. Search for a method which performs the desired option you want
int a = Integer.parseInt("5"); // using the Integer class method parseInt to convert a String to an int
Number constants
The last major problem when dealing with casts are number constants.
float a = 3.5; // 3.5 is actually a double literal, invalid implicit cast int b = 3L; // 3 is actually a long literal, invalid implicit cast byte c = 256; // out of the range for a byte, treated as an int literal, invalid implicit cast
There are two solutions to this problem:
1. Use the "general" solution of specifying an explicit cast.
float a = (float) 3.5; int b = (int) 3L; byte c = (byte) 256;
byte - none (must be in the range of a byte)
short - none (must be in the range of a short)
int - none (must be in the range of an int)
long - 'L' (must be in the range of a long)
float - 'f'
double - none
float a = 3.5f; int b = 3; long c = 1000000000000L; // there's no appropriate equivalent for this case since it's basically a guaranteed loss of precision // byte c = 256;