Auto-boxing followed by Widening in Java - java

Following program prints Object as output, and when I remove the overloaded method contains Object as parameters, following compile time error is there:
The method m1(Long) in the type LangPackage is not applicable for the
arguments (int)
public class A {
public static void main(String args[])
{
int x = 0;
m1(x);
}
static void m1(Long l) {
System.out.println("long");
}
static void m1(Object l) {
System.out.println("Object");
}
}
My query is why auto-boxing followed by widening is allowed for Objects not for Long type

auto-boxing boxes an int to an Integer.
An Integer is an Object, but it's not a Long. Therefore static void m1(Long l) cannot be chosen.
If you would call the method with a long parameter (i.e. if x would be a long), it would be auto-boxed to Long, and static void m1(Long l) would be preferred over static void m1(Object l).

If you call m1 with a long, the output is long:
m1(1L);
If you call with an integer - m1(1) - Java will choose the method with the Object parameter.
If you change input parameter from Long to long, the output is long for m1(1):
static void m1(long l) {
This works because int and long (not Integer and Long) are primitive types and Java converts from int to long in a case like this.
Integer does not extend Long, or vice versa. But both extend Number, so if you change to:
static void m1(Number n) {
That method will be called for m1(1)

https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
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.

Related

How do I provide byte value specifically to a class having m1(byte) and m1(int) signatures

public class HelloWorld
{
public void m1(int i)
{
System.out.println("int-arg");
}
public void m1(byte j)
{
System.out.println("byte-arg");
}
public static void main(String []args)
{
HelloWorld n=new HelloWorld();
n.m1(12);
}
}
O/P: int-arg
Question: 12 is int type and byte type too. so in this case int is the exact match everytime. so what value should I provide if I want to call m1(byte) method?
Thanks.
You can either declare it with type or cast it
byte b = 12;
n.m1(b);
or cast
n.m1((byte)b);
As others have said, you will need to cast it.
In Java, plain numbers (ex: 12) are int by default, if the number has decimals (ex: 12.0), it will default to float double type (thank you #Sushil for the correction). There are suffixed to force some types, but not for all types (ex: 12L is long, 12.0f is float).
You'll need to cast prior to passing the value.
n.m1((byte)12);

Why does the method with byte parameter calls the method with short, why not int?

class Practice {
public static void aMethod (int val) { System.out.println("int"); }
public static void aMethod (short val) { System.out.println("short"); }
public static void aMethod (Object val) { System.out.println("object"); }
public static void aMethod (String val) { System.out.println("String"); }
byte b = 9;
Practice.aMethod(b); // first call My guess:don't know? it is short but why
Practice.aMethod(9); // second call My guess:int correct
Integer i = 9;
Practice.aMethod(i); // third call My guess: Object correct
Practice.aMethod("9"); // fourth call My guess: String correct
}
Why does the method called with byte (b) as a parameter calls the method with short?
Java automatically chooses the best applicable method for your type.
In this case you are providing a byte, which is the smallest possible data type. The conversion for all data types would look like:
int - Possible, direct conversion from byte to int
short - Possible, direct conversion from byte to short
String - Not possible, byte is no String (usage of parsing-methods is needed)
Object - Possible, conversion from byte to Byte to Object
Java now automatically chooses the conversion to the narrowest type.
The conversion to Object goes in favor of int and short since it introduces a whole object, a huge overhead.
Finally short is chosen instead of int since it is smaller. A byte fits inside a short, which itself fits inside an int.
byte - from -2^(7) to 2^(7)-1
short - from -2^(15) to 2^(16)-1
int - from -2^(31) to 2^(31)-1
(The difference is larger but then you wouldn't see anything in the image)

function overloading unsolved example

public class Roshni {
void sum(int i, int j) {
System.out.println("inside 1st i = " + i);
}
void sum(short i, int j) {
System.out.println("inside 2nd i = " + i);
}
public static void main(String s[]) {
Roshni r = new Roshni();
r.sum(5, 5);
}
}
now my question is why sum(int i,int j) is being called even if the first command line parameter 5 comes under the range of short whereas while i am typecasting like this r.sum(Short(5),5); then it is calling sum(short i,int j)
This isn't a matter of overload resolution - your method with the short parameter isn't even applicable. Here's an example:
public class Test {
public static void foo(short x) {
}
public static void main(String[] args) throws Exception {
foo(5); // Error
}
}
This gives a compile-time error:
Test.java:10: error: incompatible types: possible lossy conversion from int to short
foo(5);
^
The type of the integer literal is int, and there's no normal implicit conversion from int to short. Now you can write:
short x = 5;
... because that's in an assignment context, where additional conversions are available:
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
That doesn't apply to method arguments, however.
Once you've got a value of type short, then overload resolution would come into play:
short x = 5;
r.sum(x, 5);
Now both methods are applicable, and the compiler will pick the second one as the more specific one following the rules of JLS 15.12.2.5.
If you specify two methods as
sum(double i,int j)
sum(short i,int j)
Now if you call sum(12.12,4) then sum(double i,int j) will be called. Its because the real values or decimal values are of double type in java. To call the sum(short i,int j) to need to additionally specify by type casting it to short.
sum(short(12.23),4)
This type casting to short will discard the higher order bits from 64 bit double value of 12.23 and pick only the last 16 bits as a short value.
In java literal integers are implicitly considered as ints.
So unless you specify it to be a short (by casting for example), it's a call for sum(int i,int j) as far as compiler is concerned.

Can please anybody explain me this Autoboxing?

Alright, here's the code :
public class Dec26 {
public static void main(String args[]) {
short a1=6;
new Dec26.go(a1);
new Dec26.go(new Integer(7));
}
void go(Short x){System.out.println("S");}
void go(Long x){System.out.println("L");}
void go(int x){System.out.println("i");}
void go(Number n){System.out.println("N");}
}
Why is the output "iN" and not "ii" ?
The Java compiler applies unboxing when an object of a wrapper class is:
Passed as a parameter to a method that expects a value of the
corresponding primitive type.
Assigned to a variable of the corresponding primitive type.
So, as there was a suitable method for Integer class, which is void go(Number n) because Number class is super class of Integer and this method accepts Integer objects as well.
So compiler didn't need to unbox the Integer to int.
Compiler chooses the closest match without autoboxing /unboxing first. It found go(Number) and did not use unboxing.

Boxing and Widening

What is the difference between these two. I know Boxing is converting primitive values to reference. What is widening. Also what should be the sequence first boxing should be done or widening should be done?
Widening wins over boxing and var-args
Boxing wins over var-args
Widening of reference variable depends on inheritance(so, Integer cannot be widened to Long. But, Integer widened to Number).
Widen and boxing is not possible
Boxing and widening is possible
var-args can be combined with either boxing or widening
Widening is transforming a variable in another with a wider type.
Widening can be done with primitive or reference types.
For example :
String -> Object
int -> long
As the JLS states :
a boxing conversion (§5.1.7) [is] optionally followed by a widening reference conversion
Resources :
JLS - Widening Primitive Conversion
JLS - Widening Reference Conversions
Widening is when assign byte to int. i.e. you are widening the data type.
Sequence must be boxing then widening.
You CANNOT widen then box (int cannot be Long).
You CAN box then widen (int can become Object via Integer)
Note: Highlighted words are from Sun Certified Java Programmer SCJP 6 - Kathy Sierra
Widening beats boxing eg. go(int) will call go(long) instead of go(Integer) if both are available
Widening beats var-args eg go(byte,byte) will call go(int,int) instead of go(byte...x) method.
Boxing beats var-args eg go(byte,byte) will call go(Byte,Byte) instead of go(byte...x) method.
widening depends on inheritance tree. Eg. go(dog) can call go(Animal)
primitive wrapper widening is not possible so go(Short) cannot call go(Integer) since they are not in the same inheritance hierarchy .
You CANNOT widen and then box. Eg. go(int) cannot call go(Long) since to call go(Long) the compiler need to convert int to Integer then Integer to Long which is not possible.(rule mentioned above)
You can box and then widen. Eg. An int can boxed to Integer and then widen to Object
Widening is the extension of data type into a wider type.
Boxing is when primitive data type is wrapped into a container object so that it can be used in Generics, mainly Collections.
Eg:
public class Widening{
public static void main(String[] args) throws Exception {
int test = 20;
myOverloadedFunction(test);
}
//static void myOverloadedFunction(long parameter) {
//System.out.println("I am primitive long");
//}
static void myOverloadedFunction(Integer parameter) {
System.out.println("i am wrapper class Integer");
}
}
Output:
i am wrapper class Integer (int is wrapped in Integer container)
Now lets uncomment another overloaded method and see:
public class Widening{
public static void main(String[] args) throws Exception {
int test = 20;
myOverloadedFunction(test);
}
static void myOverloadedFunction(long parameter) {
System.out.println("I am primitive long");
}
static void myOverloadedFunction(Integer parameter) {
System.out.println("i am wrapper class Integer");
}
}
Output: I am primitive long
Compiler precedence is widening over autoboxing.
Reference
Widening is transforming a primitive or non primitive to a wider type (i.e. one that can hold more bytes).
Example:
short -> int
String -> Object
But, int -> Integer is not widening; it's boxing. Widening has a higher priority than boxing. Also both widening and boxing can't be done together, i.e.
int -> Long // cannot be done - both widening and boxing
int -> long // can be done - only widening
I think the order is pretty fascinating. I made out the following playground to see every possible combination. This are my functions:
static void doSomeThing(short i) {
System.out.println("short");
}
static void doSomeThing(short... i) {
System.out.println("short...");
}
static void doSomeThing(Short i) {
System.out.println("SHORT");
}
static void doSomeThing(Short... i) {
System.out.println("SHORT...");
}
static void doSomeThing(long i) {
System.out.println("long");
}
static void doSomeThing(long... i) {
System.out.println("long...");
}
static void doSomeThing(Long i) {
System.out.println("LONG");
}
static void doSomeThing(Long... i) {
System.out.println("LONG...");
}
static void doSomeThing(int i) {
System.out.println("int");
}
static void doSomeThing(int... i) {
System.out.println("int...");
}
static void doSomeThing(Integer i) {
System.out.println("INTEGER");
}
static void doSomeThing(Integer... i) {
System.out.println("INTEGER...");
}
static void doSomeThing(Object i) {
System.out.println("Object");
}
static void doSomeThing(Object... i) {
System.out.println("Object...");
}
Rules:
1.Searches for exactly the same type (int -> int)
2.Widening (int -> long)
3.Boxing (int-> Integer, it is NEVER possible to implicit box AND wide (int -> Long NOT possible without cast))
!!Multiple boxing go BEFORE var args!!
int -> Object will be chosen before int -> int...
4.Var args (int -> int...)
5.Widening + var args (int -> long...)
6.Boxing + var args (int -> Integer...)
7.Boxing + widening + var args (int -> Object...)
public class Main{
public static void main(String...args) {
//primitive int
int i = 0;
doSomeThing(i); //int
//commented out doSomeThing(int i){}
doSomeThing(i); //long. It is not possible to narrow, so short, short... Short and Short... will NEVER be called when the input is larger than a short.
//commented out doSomeThing(long i){}
doSomeThing(i); //INTEGER
//commented out doSomething(Integer i){}
doSomeThing(i); //Object. Notice that there can be multiple boxing before moving to var args
//Error occured: compiler if confused: can either execute int..., long..., Object... or Integer...
//Object... and Integer... are commented out, because in the real world int... will be called first
doSomeThing(i); //int...
//commented out int...
doSomeThing(i); //long...
//commented out long... and uncommented Integer...
doSomeThing(i); //Integer...
//commented out Integer... and uncommented Object...
doSomeThing(i); //Object...
//Integer
//Integer
Integer i = new Integer(0);
doSomeThing(i); //INTEGER
//commented out doSomeThing(Integer i)
doSomeThing(i); //Object
//commented out doSomeThing(Object i)
doSomeThing(i); //int
//commented out doSomeThing(int i)
doSomeThing(i); //long so NOT int... it goes widening again
//commented out doSomeThing(long i)
//Error occured: compliler refused: not both have int..., long..., Integer... and Object...
//int... and long... are commented out
doSomeThing(i); //INTEGER...
//commented out doSomeThing(Integer... i)
doSomeThing(i); //Object...
//commented out doSomeThing(Object... i)
//uncommented doSomeThing(int... and long...)
doSomeThing(i); //int...
//uncommented doSomeThing(int... i)
doSomeThing(i); //long...
}

Categories