Casting between primitive Java types

Changing a value from one data type to a variable of another type is known as data type conversion.

There are two types of casting,

  1. Primitive Type Casting
  2. Reference Type Casting

Primitive Type Casting

Primitive type casting in Java refers to the process of converting the value of one primitive type to another primitive type. This is commonly encountered when dealing with numeric data types, where you may need to convert, for example, an integer to a floating-point number. However, it's important to note that boolean primitive type cannot be used in a cast because its values are strictly limited to true or false and cannot be converted to other data types through casting operations.

There are two basic types of Primitive Type Casting widening and narrowing.

Widening conversions (Implicit casting)

Widening conversion, also known as implicit casting, refers to the process of converting a value from a narrower (lower size) data type to a value of a broader (higher size) data type without any loss of information. This type of conversion is automatically handled by the Java compiler, as it is safe and does not result in any data loss. For example, converting an integer (int) to a long or a float to a double are examples of widening conversions.

int i = 1000; double j = i;

In above example, an Automatic Type Casting take place, that is an integer variable (4 Byte) converted into double variable(8 Byte). The casting happened from a lower data type to a higher data type, so there is no data loss .

Widening conversions in Java

From a byte to a short, an int, a long, a float, or a double From a short to an int, a long, a float, or a double From a char to an int, a long, a float, or a double From an int to a long, a float, or a double From a long to a float or a double From a float to a double

NOTE: A widening conversion of an int or a long value to a float value , or of a long value to double value, may result in loss of precision . That is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode.

Narrowing Conversions (Explicit Casting)

Narrowing conversion refers to the process of converting a value from a broader data type (higher size) to a narrower data type (lower size). Unlike widening conversion, narrowing conversion can result in loss of information, as the target data type may not be able to fully represent the original value. Due to the potential loss of information, narrowing conversion is not done implicitly by the Java Virtual Machine (JVM) and requires explicit casting using parentheses and the desired target data type. It is essential to be cautious when performing narrowing conversions to avoid data loss and unexpected results in the program.

double i = 100.7; int j = (int) i;

In above example a double variable(8 Byte) converted into integer variable (4 Byte) . The casting happened from a higher data type to a lower data type, so can result in loss of information.

Narrowing conversions in Java

From a byte to a char From a short to a byte or a char From a char to a byte or a short From an int to a byte, a short, or a char From a long to a byte, a short, a char, or an int From a float to a byte, a short, a char, an int, or a long From a double to a byte, a short, a char, an int, a long, or a float

An implicit conversion is performed automatically, with no additional input from the developer. An explicit conversion , on the other hand, is not performed automatically and is, instead, dictated by the developer.

Reference Type Casting

objects of one class can be cast into objects of another class when there is an inheritance relationship between the source and destination classes. This type of casting is known as "upcasting" and "downcasting." Upcasting involves casting an object of a subclass to its superclass type, while downcasting involves casting an object of a superclass to its subclass type.

During compile-time, the compiler checks the validity of the cast based on the class hierarchy and ensures that the casting is done only between classes that have an inheritance relationship. If the casting is not allowed, the compiler raises a compile-time error.

At runtime, when the program is executed, the JVM verifies the validity of the cast by checking if the actual object being cast is an instance of the target class or its subclass. If the casting is not valid, a ClassCastException is thrown.

To ensure type safety and prevent runtime exceptions, it is essential to use the instanceof keyword to check the compatibility of the object before performing a downcasting operation. Following the compile-time and runtime rules for casting in Java is crucial to maintain the integrity of the program and ensure proper object handling with polymorphism. There are two types of Reference Type Casting in Java, they are :

  1. Upcasting
  2. Downcasting

Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.

Upcasting

Upcasting is the process of converting an object of a subclass into an object of its superclass. In Java, when performing upcasting, an explicit cast is not required, and you can directly assign the object to the supertype. The compiler will automatically understand and perform the cast. This allows us to treat the object at a more generic level. However, if desired, we can still include an explicit cast without any problems.

Downcasting

Downcasting is the process of converting an object of a superclass to an object of its subclass. This is a common type of cast. By performing downcasting, we inform the compiler that the value stored in the base object is of the superclass type, and then we request the runtime to assign the value to the subclass. As a result of downcasting, we gain access to the methods specific to the subclass on that object. It is crucial to be cautious when performing downcasting to ensure that the object being cast is of the correct subtype to avoid potential runtime errors.

Conclusion

Casting in Java allows for flexibility and polymorphism in object handling, but it is crucial to follow the compile-time and runtime rules to ensure type safety and avoid runtime exceptions.