Why compiler thinks `byte...` and `char...` are ambigious [duplicate] - java

This question already has answers here:
Method overloading with variable arguments (varargs) [duplicate]
(4 answers)
Varargs Java Ambiguous Call
(2 answers)
Closed 4 years ago.
Similar question about var-args in method signatures was asked few times (1, 2) but there is a corner case I don't get it. The compiler can distinguish between int... and long... overloaded method signatures and calls the method with smaller type.
However byte and char are clearly not the same size, yet the compiler complains that below test() method is ambiguous:
static void test(byte... v) { System.out.println("Byte"); }
static void test(char... v) { System.out.println("Char"); }
public static void main(String[] args) {
test(); // Error:(7, 5) java: reference to test is ambiguous
// both method test(byte...) in App and method test(char...) in App match
}
Same happens for short... and char... however int... and char... are not ambiguous.
Why is char... considered ambiguous with byte... or short... while by themselves byte... and short... are distinguishable in method signature?
static void test(byte... v) { System.out.println("Byte"); }
static void test(short... v) { System.out.println("Short"); }
public static void main(String[] args) {
test(); // Byte
}

You didn't include any arguments in the call so how would the compiler know the type?
Also
"Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (ยง5.1.2)."
https://docs.oracle.com/javase/specs/jls/se10/html/jls-5.html#jls-5.6
The compiler does not see the types as equivalent. It promotes them to int. Since both forms promote to int it doesn't know which to use.
Try explicitly casting the arguments to resolve the ambiguity.

The test function is overloaded. You need to pass an appropriate parameter so that the compiler may infer which method to call. Additionally, both byte and char are equally specific primitives for varargs (by that I mean compiler treats them similarly) which thereby causes ambiguity.

Related

type conversion at method calling

public class Demo1{
public static void main(String[] args){
show('A','A');
}
public static void show(char c, long a){
System.out.println("long-char");
}
public static void show(char c, int a){
System.out.println("char-int");
}
}
Output : char-int
But when I change the order of parameters in the first show() method (replacing
public static void show(char c, long a){} with public static void show(long a, char c) {}), I get a compilation error.
The compiler says that it is an ambiguous method call, because it is.
The general approach taken for overload resolution is to find the most specific applicable method, given the number and types of the actual parameters.
In the first case, the two methods have char as their first parameter; so it is only down to choosing whether the int or long overload is more specific, given that the actual parameter is a char: it is the int overload which is more specific, because int is narrower than long.
In the second case, one method has char as the first parameter; one method has char as the second parameter. So, given that the actual parameters are both chars, one of the parameters has to be converted (widened) to invoke either of the methods.
The language spec does not define that one is more specific than the other in such a case; they are both considered equally applicable, so the method call is ambiguous, and thus is a compile-time error.

Why method call is giving error?

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.

Java varargs method overloading compiler error - ambiguity?

So, today I've been testing Java's overloading techniques and I've come across ambiguity which I can't explain. Basically, when there is a vararg method with primitive and its corresponding wrapper the compiler complains and can't decide which one to choose and I don't understand why? It's easy for human to decide and not for compiler?
Here is the fragment which works for non-vararg parameters:
public static void main(String[] args)
{
int a = 14;
Integer b = new Integer(14);
stuff(a);
stuff(b);
}
static void stuff(Integer arg) { System.out.println("Integer"); }
static void stuff(int arg) { System.out.println("int"); }
And here comes the vararg which complains and cries like a baby:
public static void main(String[] args)
{
int a = 14;
Integer b = new Integer(14);
stuff(a); // Doesn't compile (ambiguity)
stuff(b); // Doesn't compile (ambiguity)
}
static void stuff(int... arg) { System.out.println("varargs int"); }
static void stuff(Integer... arg) { System.out.println("varargs Integer"); }
Consider the following two hypothetical calls to stuff():
int a = 14;
Integer b = new Integer(14);
stuff(a, b);
stuff(b, a);
How does the compiler even know which method should be called here? Because of autoboxing rules, either call could be referring to either overloaded method.
Update:
My answer is logically correct, or at least on the right track, but for a more formal answer we can refer to this SO question:
Why ambiguous error when using varargs overloading with primitive type and wrapper class?
The two varargs method are invoked in loose invocation context. As a result, the compiler will attempt to find the more specific method via JLS 15.12.2.5 Choosing the Most Specific Method. However, since neither int nor Integer are subtypes of one another, the compiler will throw an error.
The problem is:
java is doing behind the scenes bridge methods (you need to verify that is you need deep info)
AND the important part, vargargs means too YOU CAN JUST NOT PASS ANY PARAMETER, so:
static void stuff(int... arg)
and
static void stuff(Integer... arg)
can both being invoked taking no parameters... so that will create some conflict about what method should the JVM invoke

Why constructor call is not ambiguous in the following example? [duplicate]

This question already has answers here:
Method overloading and choosing the most specific type
(9 answers)
Closed 8 years ago.
class Test {
public Test(Object obj) {
System.out.println("Object");
}
public Test(String s) {
System.out.println("String");
}
public static void main(String[] args) {
new Test(null); //prints String. Why not Object?
}
}
If I add another constructor with argument of type Integer ,or, for that matter any other type, calling new Test(null); results in compilation error - The constructor Test(Object) is ambiguous. Why no error is generated for the above example? On executing it, constructor with argument String is called. Why constructor with argument type Object is not called? How this ambiguity is resolved?
//prints String. Why not Object?
Because compiler choose most specific type.
If I add another constructor with argument of type Integer ,or, for
that matter any other type, calling new Test(null); results in
compilation error - The constructor Test(Object) is ambiguous.
Now String and Integer are in the same level in the object hierarchy, So, compiler can't choose one out of those two
Because it is determined by the most specific type of the parameter.
Since String is subclass of Object, and null is subtype of anything, then the second constructor is called, because String is more specific than Object.
Compiler is designed to pick up the overloaded method that very closely matches the Value sent in parameter.

Java Overloading concept [duplicate]

This question already has answers here:
Java method dispatch with null argument
(4 answers)
Understanding which constructor is chosen and why
(4 answers)
Closed 9 years ago.
When I run this code it prints String. My question is why there is no compile time error?
Default value of Object and as well as String is null. Then why not compiler says Reference to method1 is ambiguous.
public class Test11
{
public static void method1(Object obj) {
System.out.println("Object");
}
public static void method1(String str) {
System.out.println("String");
}
public static void main(String[] arr ) {
method1(null);
}
}
From this answer:
There, you will notice that this is a compile-time task. The JLS says in subsection 15.12.2:
This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable There may be more than one such method, in which case the most specific one is chosen.
The compiler will look at all the possible overloads of the method that could match the parameters you pass. If one of them is more specific than all the others then it will be chosen, it's only considered ambiguous if there is no single most specific overload.
In your example there are two possible overloads, method1(Object) and method1(String). Since String is more specific than Object there's no ambiguity, and the String option will be chosen. If there were a third overload such as method1(Integer) then there is no longer a single most specific choice for the call method1(null), and the compiler would generate an error.
Well in one sentence
In case of Overloaded methods compiler chooses the method with most
specific type, as String is the most specific type of Object compiler
will invoke the method which takes string as an argument
public class Test11
{
public static void method1(String str)//here str is the object of string
{
System.out.println("String");
}
public static void method1(Object obj)//here this is a common object not specified
{
System.out.println("Object");
}
public static void main(String[] arr )
{
Test11 t=new Test11();
String null1=new String();
method1(null1);
method1(t);
}
}
output is :
String
Object
//null1- is a string object if u pass this it will call method1(String str) only because u pass string object
//t-is general object if u pass this it will call method1(Object obj)only because u pass class objct so it will pass object as parameter

Categories