Widening and Boxing Java primitives.
I know it is not possible to widen a wrapper class from one to another as they are not from the same inheritence tree. Why though is it not possible to widen a primitive to another primitive type and autobox the widened primitive?
Given that a byte argument can be passed to a method that expects an int, why cant the byte in the following example be widened to an int and then boxed to an Integer?
class ScjpTest{
static void goInteger(Integer x){
System.out.println("Going with an Integer");
}
static void goInt(int x){
System.out.println("Going with an int");
}
public static void main(String args[]){
byte b = 5;
goInt(b);
goInteger(b);
}
}
In the above example, goInt(b)
is accepted by the compiler but goInteger(b)
is rejected.
In Java, when primitive values are boxed into a wrapper object, certain values (any boolean, any byte, any char from 0 to 127, and any short or int between -128 and 127) are interned, and any two boxing conversions of one of these values are guaranteed to result in the same object.
Widening − Converting a lower datatype to a higher datatype is known as widening. In this case the casting/conversion is done automatically therefore, it is known as implicit type casting. In this case both datatypes should be compatible with each other.
Boxing is the mechanism (ie, from int to Integer ); autoboxing is the feature of the compiler by which it generates boxing code for you.
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called unboxing.
The java language only supports some level of carelessness.
I believe that autoboxing was added to support developer carelessness. Specifically in situations like this: "I need an Integer as a parmeter to the method I want to call, but I have an int. Somehow, new Integer(int) never pops into my head. Instead, I'll just send an int and the java compiler will do the new Integer() call for me. Thanks java carelessness support group!"
The folks designing autoboxing were willing to support 1 level of carelessness (int => Integer and back), but were not willing to support auto casting of smaller primitive types to larger primitive types in conjunction with automatic creation and extration from primitive type wrapper classes. I suspect the descision matrix for this would be somewhat larger than the decision matrix for the current autoboxing scheme.
Why? Because boxing / autoboxing is only some compiler sugar and not a new type system. It's badly designed and causes trouble at least as often as it simplifies things.
But here are some workarounds for your compile error:
goInteger((int) b);
// these are equivalent
goInteger(((Byte) b).intValue());
goInteger(Byte.valueOf(b).intValue());
If we allow too many magic conversions, it'll get very confusing.
The existing conversion rules are already more than people care to understand. Even the language spec got it wrong! See this funny example Java casting: is the compiler wrong, or is the language spec wrong, or am I wrong?
In Java, Boxing + Widening is allowed, but not Widening + Boxing.. For goInteger to be accepted, first widening of primitive datatype (byte -> int) is required, which ok and then Boxing is required (int -> Integer). Please find the 5 golden ruled of Widening, Boxing and Vararg:
- Primitive Widening > Boxing > Varargs.
- Widening and Boxing (WB) not allowed.
- Boxing and Widening (BW) allowed.
- While overloading, Widening + vararg and Boxing + vararg can only be used in a mutually exclusive manner i.e. not together.
- Widening between wrapper classes not allowed
I hope this will help you. With regards, Sudipta Deb.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With