Explicit type casting example in Java
Reference vs Object vs Types
The key, for me, is understanding the difference between an object and its references, or put in other words the difference between an object and its types.
When we create an object in Java, we declare its true nature, which will never change (e.g. new Truck()
). But any given object in Java is likely to have multiple types. Some of these types are obviously given by the class hierarchy, others are not so obvious (i.e. generics, arrays).
Specifically for reference types, the class hierarchy dictates the subtyping rules. For instance in your example all trucks are heavy vehicles, and all heavy vehicles are vehicles. Therefore, this hierarchy of is-a relationships dictates that a truck has multiple compatible types.
When we create a Truck
, we define a "reference" to get access to it. This reference must have one of those compatible types.
Truck t = new Truck(); //or
HeavyVehicle hv = new Truck(); //or
Vehicle h = new Truck() //or
Object o = new Truck();
So the key point here is the realization that the reference to the object is not the object itself. The nature of the object being created is never going to change. But we can use different kinds of compatible references to gain access to the object. This is one of the features of polymorphism here. The same object may be accessed through references of different "compatible" types.
When we do any kind of casting, we are simply assuming the nature of this compatibility between different types of references.
Upcasting or Widening Reference Conversion
Now, having a reference of type Truck
, we can easily conclude that it's always compatible with a reference of type Vehicle
, because all Trucks are Vehicles. Therefore, we could upcast the reference, without using an explicit cast.
Truck t = new Truck();
Vehicle v = t;
It is also called a widening reference conversion, basically because as you go up in the type hierarchy, the type gets more general.
You could use an explicit cast here if you wanted, but it would be unnecessary. We can see that the actual object being referenced by t
and v
is the same. It is, and will always be a Truck
.
Downcasting or Narrowing Reference Conversion
Now, having a reference of type Vechicle
we cannot "safely" conclude that it actually references a Truck
. After all it may also reference some other form of Vehicle. For instance
Vehicle v = new Sedan(); //a light vehicle
If you find the v
reference somewhere in your code without knowing to which specific object it is referencing, you cannot "safely" argument whether it points to a Truck
or to a Sedan
or any other kind of vehicle.
The compiler knows well that it cannot give any guarantees about the true nature of the object being referenced. But the programmer, by reading the code, may be sure of what s/he is doing. Like in the case above, you can clearly see that Vehicle v
is referencing a Sedan
.
In those cases, we can do a downcast. We call it that way because we are going down the type hierarchy. We also call this a narrowing reference conversion. We could say
Sedan s = (Sedan) v;
This always requires an explicit cast, because the compiler cannot be sure this is safe and that's why this is like asking the programmer, "are you sure of what you are doing?". If you lie to the compiler you will throw you a ClassCastException
at run time, when this code is executed.
Other Kinds of Subtyping Rules
There are other rules of subtyping in Java. For instance, there is also a concept called numeric promotion that automatically coerce numbers in expressions. Like in
double d = 5 + 6.0;
In this case an expression composed of two different types, integer and double, upcasts/coerces the integer to a double before evaluating the expression, resulting in a double value.
You may also do primitive upcasting and downcasting. As in
int a = 10;
double b = a; //upcasting
int c = (int) b; //downcasting
In these cases, an explicit cast is required when information can be lost.
Some subtyping rules may not be so evident, like in the cases of arrays. For instance, all reference arrays are subtypes of Object[]
, but primitive arrays are not.
And in the case of generics, particularly with the use of wildcards like super
and extends
, things get even more complicated. Like in
List<Integer> a = new ArrayList<>();
List<? extends Number> b = a;
List<Object> c = new ArrayList<>();
List<? super Number> d = c;
Where the type of a
is a subtype of the type of b
. And the type of c
is a subtype of the type of d
.
Using covariance, wherever List<? extends Number>
appears you can pass a List<Integer>
, therefore List<Integer>
is a subtype of List<? extends Number>
.
Contravariance produce a similar effect and wherever the type List<? super Number>
appears, you could pass a List<Object>
, which makes of List<Object>
a subtype of List<? super Number>
.
And also boxing and unboxing are subject to some casting rules (yet again this is also some form of coercion in my opinion).
why explicit type casting required from double to float but not from int to byte?
In the integer version, the compiler knows that all the data in the number 5
can be stored in a byte
. No information is lost. That's not always true for floating point values. For example, 0.1f
isn't equal to 0.1d
.
Now for the example, you've given, the decimal value 5.5 is exactly represented in both float
and double
, so you could argue that in that case, no information is lost - but it would be pretty odd for the language specification to have to make this valid:
float f = 5.5;
but this invalid:
float f = 5.6;
The language specification is happy to talk about whether a number fits within the range of float
/double
(although even that isn't as simple as you might expect) but when it comes to whether a literal can be exactly represented, I don't think it ever goes into detail.
Java explicit type cast for the floating-point division
No, that's not an explicit typecast. You would want to use something like this:
result = ((double) num1) / ((double) num2);
Actually, because of the widening rules for the /
operator, you would only need one of those explicit casts, but there's no harm in having both. In fact, because the cast operator ()
has higher precedence than the division operator /
, you could write it as:
result = (double) num1 / num2;
which combines an explicit cast of the numerator and an implicit cast of the denominator.
Explicit casting for a loop
Hello and welcome to java coding.
Type casting means to assign a variable to a new type even if it was predefined.
Take an Double
double number = 4.5;
Now you gonna store that number as integer.
int falsyNumber = number;
This will produce an error, because your integer is not capable of storing values behind the decimal point. The compiler will propably stop execution by default and call sth. like "you gonna lose information if you do that, is it intentional?"
Therefor you need to say "YES, I dont care about those lost data and need that extra space of memory that i can free with that.."
So you have to explicitly typecast that variable to be Integer.
int falsyNumber = (int)number;
The brackets hold the type, and number is used as it was of that type (in this line at least).
So your compiler wont show an error here, but your output will be 4
, because you lose that data than can obviously not be stored by integer.
Many words, for such an easy line. You typecast your double value and store it into (another) variable of the type float.
double input = 3.983243242423; // that is your input stored
float numberToCalulateWith = (float)input; // here it truncates eventually
It is to be said, in some cases the difference wont be that noticeable. Because you stored a "4" as double and then cast it to float you will still have a 4. But if its not such an easy number you will lose data, and the goal of this exercise is to see, from when on you lose it.
Explicit Type Conversion of sub class object to super class in java
The explicit type casting of the reference, not the object) is redundant and some IDEs will suggest you drop it.
If you do
A a1 = (A)b;
You can still do
B b2 = (B) A;
to cast the reference back to type of B.
Note: the object is not altered in any way and is always a B
there is no scenario in java where you would need it?
The only time you need an upcast is in method selection.
void method(Object o) { }
void method(String s) { }
method("hello"); // calls method(String)
method((Object) "hello"); // calls method(Object)
Implicit type casting in Java
They are added as ints (like they would if you executed i+j
without an assignment), and then casted to float because of the assignment.
However if you executed float k = (float) i + j
then j
would be casted to a float because the left hand side of the addition is a float ... Same for float k = 1.0f*i + j
Makes sense?
Related Topics
Converting Array of Primitives to Array of Containers in Java
How to List All Classes Loaded in a Specific Class Loader
How Can My Java Program Store Files Inside of Its .Jar File
Java Ternary Without Assignment
JPA Onetomany Not Deleting Child
Class.Getresource() Returns Null
Gson Custom Seralizer for One Variable (Of Many) in an Object Using Typeadapter
Java Fileoutputstream Create File If Not Exists
Java: How to Indent Xml Generated by Transformer
Using Javamail to Connect to Gmail Smtp Server Ignores Specified Port and Tries to Use 25
Why Main() Method Is Needed in Java Main Class
How to Round a Double to Two Decimal Places in Java
How to Parse Case-Insensitive Strings with Jsr310 Datetimeformatter
Browse for Image File and Display It Using Java Swing
How to Write a Key Listener to Track All Keystrokes in Java
How to Enumerate Ip Addresses of All Enabled Nic Cards from Java