Byte typecasting - java

It is a basic question, but I couldn't get a the proper answer. I am thinking it is because of primitive types auto type casting
Why would the below statement invokes the print(int x) method and not print (char x) method.
public class Overloading {
public static void main(String args[])
{
byte b='x';
print(b);
}
public static void print(int x)
{
System.out.println("Inside int Print "+x);
}
public static void print(char x)
{
System.out.println("Inside char Print "+x);
}
public static void print(float x)
{
System.out.println("Inside float Print "+x);
}
}

The conversion that may be used for this method invocation conversion is a widening primitive conversion :
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
You see there is no byte to char path. This isn't a priority matter : if you remove the function taking an int as parameter, your code won't compile.

byte will auto convert to int not to char
primitive types are called the widening primitive conversions:
byte to short, int, long, float, or double
reference link section 5.1.2

compiler chooses an overloaded method this way
byte->short->int->long
interestingly, if you leave only print(char x) you'll get compiler error
for char it is
char->int->long

Related

Why is method with int parameter used instead of method with Short parameter? [duplicate]

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.

Auto-boxing followed by Widening in 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.

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.

Short to int automatic promotion

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.

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