Wednesday, January 30, 2019

Java tutorial: Typecasting(primitive types)

Typecasting(primitive types)

Type casting in java is casting a type explicitly or implicitly to another type in their respective data type group. In other words, you can only cast a primitive type to another primitive type and an object type to another object type, for example, you can cast int to float and class instance to another class instance. 

In this tutorial we will focus on casting primitive data types, casting reference types will be covered in future tutorials. Also, you can somewhat cast a primitive to a reference type, for example, int primitive to Integer reference type and that topic will be also covered in future tutorials. There are two distinct type of typecasting in java, the widecast or upcast and the narrowcast or downcast.

Upcast is also called implicit conversion because once you convert a specific type to another type it will be converted automatically without writing some extra explicit cast syntax. Downcast or explicit conversion, on the other hand, needs an extra explicit syntax to cast a specific type to another type with a possible of data loss.

You might wonder: "if downcast can cause data loss then it is not a good idea to do a downcast because it will ruin the value of the data that i want to convert". Well, that's one of the possible reason why java restricts automatic conversion when doing a downcast, In other words, We are downcasting because we know what we are doing.

These are the several reasons that can cause data loss when downcasting: casting a floating-point to integer for example casting float to int, when you cast float to int the decimal or fractional part of that float will be lost. Next is, casting a large data value that exceed the size of the destination type. For example, if you convert int to byte and the int value is larger than the size of the byte that it can hold, the int value may lose some of its value.

Here's a figure guide for java primitive type casting.







To clearly understand typecasting and all of the thing that we discussed let's test it on actual coding. First create a java source file in our workspace folder, then name it "SampleConversion" and then write the basic code structure of our source file the public class and the main method.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   
 }

}
Then, let's declare and initialize some primitive variables in the main method.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 0;
   byte byteVar = 0;
 }

}
Notice that we initialized the variable in the main instead of initializing it on the top of the main method. These variables are called a local variables. Local variables will cease to exist when the execution leaves the method where they reside.

Upcasting Primitive Type

Now, Let's try the upcast, to do that assign the byte variable to the int variable then compile and run.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   byte byteVar = 100;
   int intVar = byteVar;

   System.out.println("byte: " + byteVar);
   System.out.println("int: " + intVar);
 }

}
As you can see the int variable has a value of 100 which is the same value of our byte variable. You might wonder that the byte variable value should move to int variable since we assigned it to int. Well, java copied byteVar value and assigned the copied value to intVar. When doing upcast or widecast be sure to follow the order of data type in the upcast figure that I showed earlier.

Downcasting Primitive Type

Next is the downcast, to do downcast follow me, let's try to downcast int to byte as an example, we did the upcast earlier and now we will be doing the downcast which is the reverse process of upcast. Assign a 100 value to the int variable then assign the int variable to byte.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 100;
   byte byteVar = intVar;

   System.out.println("byte: " + byteVar);
   System.out.println("int: " + intVar);
 }

}

When we run this now we will receive an error, try to run the code. As you can see an error occurred, I already demonstrated this in previous tutorial so I suppose you're familiar with it. To remove that error type, we need to specify the target type in parentheses like this (target-type) before the primitive type that we want to convert, then compile and run.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 100;
   byte byteVar = (byte)intVar;

   System.out.println("byte: " + byteVar);
   System.out.println("int: " + intVar);
 }

}

As you can see we discarded the error, we cast an int value to byte and our program runs normally.

Downcasting a Value That Exceeds Destination's Capacity

Now, let's try to convert a larger int value to byte let's try 1000, If we assign 1000 to a byte data loss will occur let's try it! change the value of int variable to 1000 then compile and run.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 1000;
   byte byteVar = (byte)intVar;

   System.out.println("byte: " + byteVar);
   System.out.println("int: " + intVar);
 }

}
As you can see the converted value is too far off from the original value. You might asked yourself "Why the converted value is -24, How's that happened?". If you want to have a deep understanding about the situation I recommend you to study decimal and binary number system, one's and two's complement, adding and subtracting binary numbers. I won't cover those topic here, those topic are not part of this tutorial maybe I will cover them in my future tutorials.

To have a better understanding on how the converted value end like that we will use the windows calculator instead of computing it manually. Open the calculator type then switch to the programmer's mode, then make sure decimal or Dec radio button is selected and select the dword radio button,we will use dword which is a 32-bit value, since int data type is 32-bit.

Switching to Programmer's mode


Setting our calculator


Then input the int value which is 1000, then click the binary or bin radio button to convert the int value to binary. Also, focus on the bits that is highlighted in red

Converting 1000 from decimal to binary


When java converts the int value to byte some bits of int value to the left will be discarded, so to do that in the calculator all we need to do is to click the byte radio button to change the bit size to 8 bits which is the size of byte data type in java.

Converting int bits to byte bits


As you can see the left bits at the left side was discarded. Then, click the dec radio button to convert the binary to decimal and as you can see the answer on the calculator is the same as the output on the console.

Converting binary to decimal


If you know how the general conversion of binary to decimal you might say that this binary is equal to 232 when converted to decimal. Well, That's true when you convert an unsigned numbers to binary, unsigned numbers means a data that has no negative value just a plain whole numbers, but we're converting a signed numbers and to convert a signed number java uses the two's complement method.

We did use two's complement on the calculator earlier and we didn't notice that we used it because the calculator did most of the work for us. The procedure that we used earlier at the calculator can also work on other integers like long and short if you have spare time try to downcast other data types like long to int or short to byte then compute the output using calculator.

Casting a Type to Character Primitive

What about casting a type to char, Since char is separated from integer data types such as byte,short,int and long and floating-point data types like float and double, downcasting is needed.

Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 1000;
   byte byteVar = (byte)intVar;
   char charVar = (char)intVar;

   System.out.println("byte: " + byteVar);
   System.out.println("int: " + intVar);
   System.out.println("char: " + charVar);
 }

}
What about downcasting a type to boolean? I suppose we can't downcast any data type to boolean. Remember, when downcasting, don't forget the parentheses then the data type in the parentheses.

Non-Floating Point Typecasting During Operation

Apart from boolean and long type, When two non-floating points are both operands in one operation, the result is upcasted to the primitive type with the highest bits which is int.

Actually, long(64 bits) is the primitive type with the highest bits to all non-floating point numbers. However, when we exclude long then the primitive type with the highest bits is int(32 bits).
public class SampleConversion{

  public static void main(String[]args){
    short s1 = 50;
    
    //valid
    int intOne = s1 + 100;
    
    //error: possible lossy conversion
    //from int to short 'cause the
    //result is int
    //short s2 = s1 + 100;
    
    //invalid
    //result is converted to int
    //byte b1 = 25;
    //short s1 = 50;
    //byte b2 = b1 + s1;
    
    //valid
    //result is long since long
    //has higher bits than int
    long longOne = 100 + 100L;
    //invalid
    //int intOne = 100 + 100L;
    
    //valid
    int intTwo = 'c' + 5;
    
    //if char and an integer literal
    //are both operands in one operation
    //and the result is gonna be stored
    //in a char variable then, the result
    //is gonna be char type
    
    //valid
    char character = 'c' + 5;
    
    //invalid
    //int intOne = 5;
    //char character = 'c' + intOne;
    
  }
}

Casting a Floating-Point to a Floating Point

Float primitive type can be upcasted to double and double can be downcasted to float.
public class SampleConversion{

  public static void main(String[]args){
    //upcasting float literal to double
    double doubleVar = 5.55f;
    System.out.println(doubleVar);
    
    //converting double literal to float
    //Just like other primitive types,
    //downcasting double to float can
    //cause data loss if the double
    //value that is gonna be casted exceeds
    //the bit range of float. Double is
    //64bits whereas float is 32bits
    float floatVar = (float)200.598333d;
    System.out.println(floatVar);
  }
}
Casting a Floating Point to a Non-Floating Point

What about casting a floating point to a non-floating point? When we cast a floating-pont to non-floating-point then the decimal places will be discarded.
Code:
public class SampleConversion
{

 public static void main(String[]args)
 {
   float floatVar = 55.5f;
   byte byteVar = (byte)floatVar;

   System.out.println("byte: " + byteVar);
 }

}
When we run this code, we will see that the decimal part of floatVar has been truncated.

Casting a Non-Floating Point to a Floating Point

Casting a non-floating point to a floating point is simply like upcasting.
public class SampleConversion
{

 public static void main(String[]args)
 {
   int intVar = 100;
   float floatVar = intVar;
   System.out.println("float: " + floatVar);
   
   long longVar = 100000L;
   double doubleVar = longVar;
   System.out.println("float: " + doubleVar);
 }

}
Floating and Non-Floating Point Conversion During Arithmetic Operation

When a floating point and a non-floating point are both operands in one operation, the result is converted to floating point.
public class SampleConversion{

  public static void main(String[]args){
    
    //error: lossy conversion from float to
    //int 'cause the result is float
    //int intOne = 20 + 30.5f;
    
    //downcast the float literal to int first
    //if you want the result to be converted
    //to int
    //int intOne = 20 + (int)30.5f;
    //System.out.println(intOne);
    
    //valid
    float floatOne = 20 + 30.5f;
    System.out.println(floatOne);
  }
}

No comments:

Post a Comment