public class Yikes1 {
public static void go(Long n) {
System.out.println("Long "); // printed
}
public static void go(Short n) {
System.out.println("Short "); // don't know why isn't this printed
}
public static void go(int n) {
System.out.println("int "); // printed
}
public static void main(String [] args) {
short y = 6;
long z = 7;
go(y);
go(z);
}
}
How does the short value got converted to int before it prints the output?
I thought widening works only when the dataype-short is not available so it looks for next available data type which is int in this case but however short datatype is defined here so how come the automatic promotion happening?
The binding sequence works as follows:
Exact match (Ex. int--> int)
Promotion (Ex. int --> long)
Autoboxing/Unboxing (Ex. int --> Integer)
Varags (Ex. int --> int...)
Okay, when there's no method, which accepts short, there's 2 options: autobox it into Short or cast to integer. JLS states, that the second option in prefered:
Method invocation contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference
conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
What you expect here is a boxing conversion, but what you get is a widening primitive conversion.
You can read more about boxing here to correctly understand the relation between short and Short.
Related
public class Yikes1 {
public static void go(Long n) {
System.out.println("Long "); // printed
}
public static void go(Short n) {
System.out.println("Short "); // don't know why isn't this printed
}
public static void go(int n) {
System.out.println("int "); // printed
}
public static void main(String [] args) {
short y = 6;
long z = 7;
go(y);
go(z);
}
}
How does the short value got converted to int before it prints the output?
I thought widening works only when the dataype-short is not available so it looks for next available data type which is int in this case but however short datatype is defined here so how come the automatic promotion happening?
The binding sequence works as follows:
Exact match (Ex. int--> int)
Promotion (Ex. int --> long)
Autoboxing/Unboxing (Ex. int --> Integer)
Varags (Ex. int --> int...)
Okay, when there's no method, which accepts short, there's 2 options: autobox it into Short or cast to integer. JLS states, that the second option in prefered:
Method invocation contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference
conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
What you expect here is a boxing conversion, but what you get is a widening primitive conversion.
You can read more about boxing here to correctly understand the relation between short and Short.
I have the following code in Java :
class Boxing
{
public static void main(String args[])
{
short s = 10;
Integer iRef = s;
}
}
Why does it produce an error in compilation? If I explicitly typecast the short to an integer in the expression, it compiles successfully. Since I'm using a short in an expression isn't the type of that supposed to be an integer by default without requiring the explicit case?
You want to have two things happening here: widening and auto-boxing.
Unfortunately, Java does only one of the two automatically. The reason for that is most likely that autoboxing was introduced fairly late (in Java5), and they had to be careful to not break existing code.
You can do
int is = s; // widening
Short sRef = s; // autoboxing
Integer iRef = (int) s; // explicit widening, then autoboxing
Here´s the documentation from JLS 5.1.7
Boxing conversion converts expressions of primitive type to corresponding expressions of reference type. Specifically, the following nine conversions are called the boxing conversions:
From type boolean to type Boolean
From type byte to type Byte
From type short to type Short
From type char to type Character
From type int to type Integer
From type long to type Long
From type float to type Float
From type double to type Double
From the null type to the null type
Basicly the direct conversion from short to Integer is not part of the autoboxing process of Java.
The autoboxing, as provided above, is only able to implicity cast the representing primitive type to it´s representing Wrapper class. Since this is not the case it will cause a compile time error.
Boxing conversion converts expressions of primitive type to corresponding expressions of reference type. Specifically, the following nine conversions are called the boxing conversions:
From type boolean to type Boolean
From type byte to type Byte
From type short to type Short
From type char to type Character
From type int to type Integer
From type long to type Long
From type float to type Float
From type double to type Double
From the null type to the null type
Reference: Conversions and Promotions Reference
In the code considered.
class Boxing
{
public static void main(String args[])
{
short s = 10;
Integer iRef = s;
}
}
Integer extends java.lang.Number. And java.lang.Short also extends java.lang.Number. But Short and Integer are not directly related if you wanted you can run the following program.
class Boxing
{
public static void main(String args[])
{
short s = 10;
Number iRef = s;
}
}
It will run without producing any error.
Java attempts to perform auto-widening, then auto-boxing, then auto-upcasting, but will not perform two of these for the same assignment. This is explained and diagrammed here, for the related case of method parameter assignment.
Why is it possible to pass a primitive to a method that takes an object? Is the primitive turned into an object? like int = Integer and boolean = Boolean?
I can call the following function:
hash(41, 0);
public static int hash(int seed, Object object)
{
int result = seed;
if(object == null)
{
return hash(result, 0);
}
else if(!isArray(object))
{
result = hash(result, object.hashCode());
}
else
{
int length = Array.getLength(object);
for(int index = 0; index < length; ++index)
{
Object item = Array.get(object, index);
// prevent looping if item in array references the array itself
if(!(item == object))
{
result = hash(result, item);
}
}
}
return result;
}
Yes, this is called a boxing conversion. The int value is "boxed" into an Integer, which is an Object. It has been available in Java since 1.5.
The JLS, Section 5.1.7 lists available boxing conversions:
Boxing conversion converts expressions of primitive type to
corresponding expressions of reference type. Specifically, the
following nine conversions are called the boxing conversions:
From type boolean to type Boolean
From type byte to type Byte
From type short to type Short
From type char to type Character
From type int to type Integer
From type long to type Long
From type float to type Float
From type double to type Double
From the null type to the null type
Additionally, the boxing conversion is allowed during method invocation conversion, which is really what's going on here. The value is being converted to another type because the int 0 is being passed to a method that expects an Object. The JLS, Section 5.3, lists boxing conversion as one method of method invocation conversion:
Method invocation contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference
conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
Yes you can. Something called autoboxing/unboxing is done by the compiler automatically. Here is an excerpt from the docs.
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.
int i = 1;
Integer boxI = i; // Autoboxing is performed automatically by the compiler
Integer ii = 1;
int i = ii; // Auto(un)boxing is performed automatically by the compiler
Yes, primitive is converted to Object and vice versa, and this concept is called boxing and unboxing. In newer versions of java this is done automatically, hence called, auto-boxing and auto-unboxing.
Oracle doc for Boxing and UnBoxing
Each primitive has corresponding Wrapper class.
int -> Integer
boolean -> Boolean
char -> Character
and so on.
I don't get why java doesn't do the widening and then autoboxing.
Integer i = (short) 10;
I would think the following would take place:
Narrowing conversion first from 10 to short.
short would then widen to int.
int would then autobox to Integer.
Instead it's a compilation error.
Example 2:
Short x = 10;
Integer y = x;
This fail too.
According to the JLS, Section 5.2, which deals with assignment conversion:
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening
reference conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
It is unable to apply two conversions at once (widening primitive conversion and boxing conversion); only one conversion can apply here, so it has to result in an error.
The solution would be to cast the short back to an int (a casting conversion), which would allow the assignment conversion to be a boxing conversion:
Integer i = (int) (short) 10;
(Or here, don't cast it to short in the first place.)
Integer i = 10;
What's going on here is a casting conversion from int to short, and then an attempted assignment conversion from short to Integer.
Assignment conversion (§5.2) allowed for boxing and then widening, but not widening and then boxing.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening
reference conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
IN java it follows sequence as "autoBoxing and then widening" only no matter if you are doing
this :
int x =5;
Object obj = x;
Or
this:
int x = 5;
Long l = x;
Widening occurs only when there is a is-a relationship.
So while applying above sequence first case is very much valid for compiler, because int would be autobox to Integer and then assigned to Object, i.e. widening (i.e. autobox first and then widening), being in Is-A relationship. But in second case if int x is autbox to Integer and the assign to Long it will not be allowed, being not is-a relationship, hence throws compilation error.
Could simulate the similar use case using overloading with respect to autoboxing and widening.
public static void m(short s) {
System.out.println("widening");
}
public static void m(Integer i) {
System.out.println("Autoboxing");
}
public static void main(String[] args) {
short x = 10;
m(x);
}
Output: widening
Hence, in nut shell we could say, Widening dominates Autoboxing in java
I have this code.
class NumberMachine {
public static void main(String [] args) {
Integer wi1 = new Integer("420");
int i = 101;
Integer wi2 = i*420/101;
if(wi1 == wi2)
System.out.print(" ==");
if(wi1.equals(wi2))
System.out.print(" equal");
float f = 1.23f;
new NumberMachine().printIt(f);
}
void printIt(Float f) {
System.out.println(" Float");
}
void printIt(double d) {
System.out.println(" double");
}
}
Why result is "equal double" but no "equal Float" ?
To determine which method should be called, the compiler goes through the following list, as detailed in the JLS #5.3 and JLS #15.12.2:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2) ==> printIt(double) works here
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference conversion ==> printIt(Float) would be called here if there was no printIt(double)
an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.
Because widening (float to double) beats boxing
printIt(Float f) accepts the Float object but printIt(double d) accepts the primitive type double.
Thus the second printIt function is called with the float cast to double.
See http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Float.html
You would let the first function be called like this:
Float f = new Float(5.0);
printIt(f);