This week I would like to talk about what happens when you force a value, which is outside the range of a certain primitive type, to be of that type.

That sounded like a tongue-twister, didn’t it? Let me remind a few concepts before. You are probably all familiar with the fact that Java has eight primitive types:

• 4 types for integers (signed): `byte`(8-bit), `short`(16-bit), `int`(32-bit), `long`(64-bit)
• 2 types for decimals (signed): `float`(32-bit), `double`(64-bit)
• 1 type for characters (not signed): `char`(16-bit)
• 1 type for booleans: `boolean`

In this post we are going to leave out of the discussion the `boolean` type.

As you can see, I have also specified the space in bits which is allocated in memory when you define a variable of that type. This also says which is the range of values that can be covered by a certain type.

For instance, the `byte` type is used to describe signed integers values and it has 8-bits for doing it, meaning it can take 28 different values. Since it needs to describe also negative values (plus `0`, of course), the range of the possible values for a `byte` variable is `[-128; 127]` (this notation means from `-128` to `127`, extremes included).

`char` and `short` are strongly related, since they both allocate 16-bits of space. The main difference here is that `short` represents signed values, so it needs to allocate some space for representing negative values as well as positive ones, while `char` can only take non-negative values, resulting in a larger set of positive numbers that can fit inside a `char` variable.

Now, when we want to fit a smaller type into a larger one there is no need for casting. Java can do that by itself. On the other hand, if you want to fit a larger type into a smaller one, you have to explicitly tell that to the compiler, by casting it.

``````short number = 23;

//OK: we are passing from a smaller to a larger type
int larger_number = number;
System.out.println(larger_number); //prints 23

//DOES NOT COMPILE: we are passing from a larger to a smaller type
byte smaller_number = number;

//OK: we are passing from a larger to a smaller type but we are casting
byte smaller_number_casting = (byte) number;
System.out.println(smaller_number_casting); //prints 23

``````

Now, what would have happened if `number`, instead of having a value of `23`, like in the example above, had a value of, let’s say, `200`, meaning a value which is outside the range of possible values for `byte`?

``````short number = 200;

//OK: we are passing from a smaller to larger type
int larger_number = number;
System.out.println(larger_number); //prints 200

//OK: we are passing from a larger to a smaller type but we are casting
byte smaller_number_casting = (byte) number;
System.out.println(smaller_number_casting); //prints  -56
``````

The first print statement will print the value of `200`, since this is a perfectly valid value for the range covered by an `int` variable. What’s interesting here is the second print statement. This will output the value `-56`!

What’s going on here? We started from a value of `200` and we ended up with `-56`. Well, we are casting `number` to be a `byte`, and this is OK, but its value is still outside the range for a `byte`, so it cannot be represented as `200`. What the compiler does is to start from the lowest value of the `byte` range (`-128`) and counting up to fill the difference between the value it has to represent and the maximum possible value it actually can represent. The reasoning steps are the following:

• We want to represent a value of `200` as a `byte`
• The `byte` maximum possible value is `127` (plus the `0`), so a total of `128` possible non-negative values
• 200-128=72
• Then the compiler starts from the lowest representable value and counts up the difference: -128+72=-56

And the mystery is resolved! This process is called overflow, meaning we are trying to represents a value which is too large with respect to the allowed range, and then it starts back from the lowest to fill the difference. The opposite is what is called underflow.

So, just remember that, once you cast, the compiler may be happy with the types of your variables, but the resulting values can be different from what you expected!

Stay tuned for our next post: Numeric Promotion.