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.
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.
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.
When I am writing this code I am getting error
public class MethodOverloading
{
void m(short i)
{
System.out.println("SHort");
}
public static void main(String[] args)
{
MethodOverloading ml=new MethodOverloading();
ml.m(10);
}
}
I am getting error that m(short) is not applicable for m(int) but when I am
assigning int value to short then no error then if am not able to pass int
value as an argument to method that accepts short then how short variable is accepting int value as below?
short d=10;
System.out.println(d);
Narrowing conversion can occur in an assignment unlike literals being passed to a method. From the JLS
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.
You have to cast the int to short, because 10 is considered like an int not a short :
ml.m((short)10);
m1.m((short) 10);
Cast the 10 (since there's no type associated with it Java assumes it's a 32-bit int instead of a 16-bit short) to a short.
This is static binding, and the assignment operator '=' is not strict on down casting.But method binder is strict on type. Just imagine you have one more method void m(int i) along with void m(int i) the method binder must bind the call to the right method. So it must be strict.
In short s = 10 case, jdk will downcast the value on compilation, so the value will be assigned to s will be down caste of short 10, also if you try to assign a real int range value say 99999999 it will not compile.
Finally static method binding is strict on type.
I am trying to understand how Overloading in JAVA works and trying to get grasp of various overloading rules that are applied in case of widening, autoboxing and varargs in JAVA. I am not able to understand what is happening in the following scenario:
package package1;
public class JustAClass {
public static void add(int a, long b) {
System.out.println("all primitives");
}
//public static void add(Integer a, long b) {
// System.out.println("Wraper int, primitive long");
//}
public static void add(int a, Long b) {
System.out.println("Primitive int, Wrapper long");
}
public static void add(Integer a, Long b){
System.out.println("All wrapper");
}
public static void main(String[] args) {
int a = 10;
Integer b = 10;
long c = 9;
Long d = 9l;
add(a,c);
add(a,d);
add(b,c);
add(b,d);
}
}
At this point, I get a compilation error at the third invocation of the add method saying The method is ambiguous for the type Error .
Why is this so? What are the rules for determining which invocation of method will work? What is exactly happening in the following case?
I feel that fourth overloaded add method should work. Please help me understand the concept behind this.
There are 3 stages to method overloading resolution. The first stage doesn't do auto-boxing/unboxing, which means methods that require boxing/unboxing of the passed parameters in order to match one of the overloaded versions of add will only be considered if no match was found that doesn't require boxing/unboxing. That's why 3 of your calls, which have a single exact match, work. Regarding add(b,c);, see below why it's ambiguous.
add(a,c); // exact match to add(int a, long b)
add(a,d); // exact match to add(int a, Long b)
add(b,c); // there is no exact match, so at least one of the passed parameters must
// be boxed or unboxed. However, by unboxing b to int or boxing
// c to Long, each of the three add methods can match, and the
// compiler doesn't know which one to prefer
add(b,d); // exact match to add(Integer a, Long b)
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...
}