Professor Hans Noodles
Level 41

# Widening and narrowing of primitive types

Hi! As you have progressed through CodeGym, you've encountered primitive types many times.
Here is a short list of what we know about them:
1. They are not objects and represent a value stored in memory
2. There are several kinds
• Whole numbers: `byte`, `short`, `int`, `long`
• Floating-point (fractional) numbers: `float` and `double`
• Logical values: `boolean`
• Symbolic values (for representing letters and numerals): `char`
3. Each type has its own range of values:

Primitive type Size in memory Value range
byte 8 bits -128 to 127
short 16 bits -32768 to 32767
char 16 bits 0 to 65536
int 32 bits -2147483648 to 2147483647
long 64 bits -9223372036854775808 to 9223372036854775807
float 32 bits (2 to the power of -149) to ((2 - (2 to the power of -23)) * 2 to the power of 127)
double 64 bits (-2 to the power of 63) to ((2 to the power of 63) - 1)
boolean 8 (when used in arrays), 32 (if not used in arrays) true or false
But in addition to having different values, they also differ in how much space they occupy in memory. An `int` takes more than a byte. And a `long` is bigger than a short. The amount of memory occupied by primitives can be compared to Russian nesting dolls: Each nesting doll has space available inside. The larger the nesting doll, the more space there is. A large nesting doll (`long`) will easy accommodate a smaller `int`. It easily fits and you don't need to do anything else. In Java, when working with primitives, this is called implicit conversion. Or put differently, it's called widening. Here's a simple example of a widening conversion:
``````
public class Main {

public static void main(String[] args) {

int bigNumber = 10000000;

byte littleNumber = 16;

bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
``````
Here we assign a byte value to an `int` variable. The assignment succeeds without any problems: the value stored in a byte takes up less memory than what an `int` can accommodate. The little nesting doll (byte value) easily fits inside the big nesting doll (`int` variable). It's a different matter if you try to do the opposite, i.e. to put a large value into a variable whose range can't accommodate such a big data type. With real nesting dolls, the number simply wouldn't fit. With Java, it can, but with nuances. Let's try putting an `int` into a `short` variable:
``````
public static void main(String[] args) {

int bigNumber = 10000000;

short littleNumber = 1000;

littleNumber = bigNumber;// Error!
System.out.println(bigNumber);
}
``````
Error! The compiler understands that you're trying to do something abnormal by shoving a large nesting doll (`int`) inside a small one (`short`). In this case, the compilation error is a warning from the compiler: "Hey, are you absolutely certain that you want to do this?" If you're certain, then you tell the compiler: "Everything is okay. I know what I'm doing!" This process is called explicit type conversion, or narrowing. To perform a narrowing conversion, you need to explicitly indicate the type that you want to convert your value to. In other words, you need to answer the compiler's question: "Well, which of these little nesting dolls do you want to put this big nesting doll into?" In our case, it looks like this:
``````
public static void main(String[] args) {

int bigNumber = 10000000;

short littleNumber = 1000;

littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
``````
We explicitly indicate that we want to put an `int` into a `short` variable and that we'll take the responsibility. Seeing that a narrower type has been explicitly indicated, the compiler performs the conversion. What's the result? Console output: -27008 That was a little unexpected. Why exactly did we get that? In fact, it's all very simple. Originally, the value was 10000000 It was stored in an `int` variable, which occupies 32 bits. This is its binary representation:
We write this value into a `short` variable, which can only store 16 bits! Accordingly, only the first 16 bits of our number will be moved there. The rest will be discarded. As a result, the short variable receives the following value
which in decimal form is equal to -27008 That is why the compiler asks you to "confirm" by indicating an explicit narrowing conversion to a specific type. First, this shows that you are taking responsibility for the result. And second, it tells the compiler how much space to allocate when converting happens. After all, in the last example, if we assigned an int value to a byte variable rather than a `short`, then we would only have 8 bits at our disposal, not 16, and the result would be different. Fractional types (`float` and `double`) have their own process for narrowing conversions. If you try casting a factional number to an integer type, the fractional part will be discarded.
``````
public static void main(String[] args) {

double d = 2.7;

long x = (int) d;
System.out.println(x);
}
``````
Console output: 2

## char

You already know that `char` is used to display individual characters.
``````
public static void main(String[] args) {

char c = '!';
char z = 'z';
char i = '8';

}
``````
But this data type has several features that are important to understand. Let's look again at the table of value ranges:
Primitive type Size in memory Value range
byte 8 bits -128 to 127
short 16 bits -32768 to 32767
char 16 bits 0 to 65536
int 32 bits -2147483648 to 2147483647
long 64 bits -9223372036854775808 to 9223372036854775807
float 32 bits (2 to the power of -149) to ((2 - (2 to the power of -23)) * 2 to the power of 127)
double 64 bits (-2 to the power of 63) to ((2 to the power of 63) - 1)
boolean 8 (when used in arrays), 32 (if not used in arrays) true or false
The range 0 to 65536 is indicated for the `char` type. But what does that mean? After all, a `char` doesn't just represent numbers, but also letters, punctuation marks… The thing is that in Java `char` values are stored in Unicode format. We already encountered Unicode in one of the previous lessons. You probably remember that Unicode is a character encoding standard that includes the symbols of almost all the written languages of the world. In other words, it's a list of special codes that represent nearly every character in any language. The entire Unicode table is very large, and, of course, there's no need to learn it by heart. Here's a small part of it: The main thing is to understand how chars are stored, and to remember that if you know the code for a particular character, you can always produce that character in your program. Let's try with some random number:
``````
public static void main(String[] args) {

int x = 32816;

char c = (char) x ;
System.out.println(c);
}
``````
Console output: This is the format used to store `char`s in Java. Each symbol corresponds to a number: a 16-bit (two-byte) numeric code. In Unicode, 32816 corresponds to the Chinese character . Make note of the following point. In this example, we used an `int` variable. It occupies 32 bits in memory, while a `char` occupies 16. Here we chose an `int`, because our number (32816) won't fit in a `short`. Although the size of a `char` (just like a `short`) is 16 bits, there are no negative numbers in the `char` range, so the "positive" part of the `char` range is twice as large (65536 instead of 32767 for the `short` type). We can use an `int` as long as our code stays below 65536. But if you create an `int` value greater than 65536, then it will occupy more than 16 bits. And this will result in a narrowing conversion
``````
char c = (char) x;
``````
the extra bits will be discarded (as discussed above) and the result will be quite unexpected.

## Special features of adding chars and integers

Let's look at an unusual example:
``````
public class Main {

public static void main(String[] args) {

char c = '1';

int i = 1;

System.out.println(i + c);
}
}
``````
Console output: 50 O_О How does that make sense? 1+1. Where did the 50 come from?! You already know that `char` values are stored in memory as numbers in the range from 0 to 65536, and that these numbers are a Unicode representation of a character. When we add a `char` and some whole-number type, the `char` is converted to the corresponding Unicode number. In our code, when we added 1 and '1', the symbol '1' was converted to its own code, which is 49 (you can verify this in the table above). Therefore, the result is 50. Let's once again take our old friend as an example, and try adding it to some number.
``````
public static void main(String[] args) {

char c = '耰';
int x = 200;

System.out.println(c + x);
}
``````
Console output: 33016 We already discovered that corresponds to 32816. And when we add this number and 200, we get our result: 33016. :) As you can see, the algorithm here is quite simple, but you shouldn't forget it.
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Robert Level 14, Debica, Poland
22 August 2021
``````
public static void main(String[] args) {

int bigNumber = 10000000;

short littleNumber = 1000;

littleNumber = bigNumber;// Error!
System.out.println(bigNumber);
}
``````
I think, there is a mistake, we want to know littleNumber, line 9, we should print littleNumber ???
Kou Shikyo Level 20, Tokyo
3 October 2020

Peter Schrijver Level 23, Hilversum, Netherlands
11 June 2020
Nice explanation, good reference material for later
Austeja Level 10, Kaunas, Lithuania
22 May 2020
Chars are really interesting. I bet one can use them very creatively.
Ashish RajAnand Level 13, Bhilai , India
21 April 2020
nice
Vahan Level 41, Tbilisi, Georgia
9 August 2019
What are the code at wright part of square in last table, as 43 * 2A? What this 2A means?
Renat Mukhametshin Level 16, Pervouralsk, Russain Federation
8 August 2019
ok, good!
8 July 2019
Same question here than Eweton. Isn't boolean just 1 or 0? there's only 1 bit needed for that haha
Ewerton Level 30, Belo Horizonte, Brasil
29 June 2019
Why would they need 32 bits for a boolean?