Related
This question already has answers here:
Is it possible to have different return types for a overloaded method?
(13 answers)
The relationship of overload and method return type in Java?
(4 answers)
Closed 6 years ago.
I am gonna put this question to have a clear idea about overloading Concept in java . As per my understanding while method resolution in overloading compiler will look for method signature that is it should have same method name and different argument types . But what if the return type is different ??
class Test{
public void m1(int i) {
System.out.println(" int arg");
}
public int m1(String s) {
System.out.println("String-arg");
return (5+10);
}
public static void main (String[] args) throws java.lang.Exception
{
Test t = new Test();
t.m1(5);
int i = t.m1("ani");
System.out.println(i);
}}
the above program is running perfectly . my doubt here is , the method m1() is it overloaded ?? it has different return type . someone please make it clear. Thanks in advance
In Java methods are identified by name and arguments' classes and amount. The return type doesn't identify the method. For this reason the following code would be illegal:
public void m1(String i) {
System.out.println(" int arg");
}
public int m1(String s) {
System.out.println("String-arg");
return (5+10);
}
If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded. (...) When a method is invoked (§15.12), the number of actual arguments (and any explicit type arguments) and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2). If the method that is to be invoked is an instance method, the actual method to be invoked will be determined at run time, using dynamic method lookup (§15.12.4)
Summarizing, two methods with the same name can return different types, however it's not being taken into account when deciding which method to call. JVM first decides which method to call and later checks if the return type of that method can be assigned to the certain variable.
Example (try to avoid such constructions):
public int pingPong(int i) {
return i;
}
public String pingPong(String s) {
return s;
}
public boolean pingPong(boolean b) {
return b;
}
if we follow the Oracle definition then yes, it is a overloaded method
here the info (emphasis mine)
The Java programming language supports overloading methods, and Java
can distinguish between methods with different method signatures. This
means that methods within a class can have the same name if they have
different parameter lists (there are some qualifications to this that
will be discussed in the lesson titled "Interfaces and Inheritance").
the fact that the method return a value or not is IRRELEVANT for the overloading definition...
another thing is here why can a method somethimes return a value and sometimes no...
this will drive crazy the people using the code, but that is another question...
This question already has answers here:
Varargs Java Ambiguous Call
(2 answers)
Closed 7 years ago.
I am surprised by seeing the output of this code :
public class File
{
public static void main(String[] args)
{
movie();
}
static void movie(double... x)
{
System.out.println("No varargs");
}
static void movie(int... x)
{
System.out.println("One argument");
}
}
It outputs,
One argument
Why is it so ?
I thought that this code would not compile because the call to movie() is ambiguous, but it runs fine and outputs One argument.
If I modify the code to:
public class File
{
public static void main(String[] args)
{
movie();
}
static void movie(boolean... x) //Changed the parameter type to boolean from double
{
System.out.println("No varargs");
}
static void movie(int... x)
{
System.out.println("One argument");
}
}
There is an error message.
Why does the first code run fine, but the second gives an error?
This behaviour is due to the fact that int is more specific than double while there is no such comparison between int and boolean.
As specified in the JLS section 15.12.2.5 (emphasis mine):
One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:
...
m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.
What more specific actually means is later defined with subtyping:
A type S is more specific than a type T for any expression if S <: T.
This means that S is more specific than T is S is a subtype of T. For primitive types, this comes down to the following properties:
double > float
float > long
long > int
int > char
int > short
short > byte
Notice that boolean is not there.
As such,
public static void main(String[] args) {
movie();
}
static void movie(int... x) { }
static void movie(short... x) { }
static void movie(double... x) { }
static void movie(byte... x) { }
compiles and movie(byte... x) will be called because it is the most specific.
However,
public static void main(String[] args) {
movie();
}
static void movie(int... x) { }
static void movie(boolean... x) { }
does not compile because boolean cannot be compared to int.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time error.
Consider movie(int...x) as M1 and movie(double...x) as M2.
Method M1 is more specific than M2 because we can call method M2 with the same inputs given to the method M1 directly without any compile time errors.
So, invocation on first method M1 is defineitly handled by the M2. Because double can handle int without any problem.
But we can not invoke M1 with the same inputs given to the method M2 and that is easy to understand.
Let's check following example,
public class Test {
public static void main(String[] args) {
movie();
}
static void movie(int... x) {
System.out.println("One argument");
}
static void movie(short... x) {
System.out.println("Short argument");
}
}
OUTPUT
Short argument
Because here short is more specific than int for method call movie().
On the other hand for boolean method call movie(); raise the confusion, because compiler can not decide which method to call because in this case there is no such point of more specific method.
I think the reason is automatic type promotion in java. By default, the type of expression is promoted to Integer type or Long type (depending upon the range) if your expression does not contain floating point.
So in first case the void expression is simply resolved to int varargs as the Integer wins the contest due to the absence of floating point value in the expression.
In second case however, compiler can not decide what to call, i.e from among the overloaded methods it can not decide which one to call with no-args.
Answer:
1. If we use objects of datatypes like int as Integer it also gives the same error. So the reason is it does not work with Object types and gives errors if no argument is specified for the function.
2. As vararg takes an argument as an Array of a given type. So that's why if you pass no arguments it takes it as an array with zero arguments and executes the integer function because it got one of the functions with an integer argument.
3. It when you put float and double for two different functions and no pass any argument then it executes the float argument function.
Solution:
Do not use object types like String, Integer, Float, Double, Boolean, and Char. Instead use int, float, double, and boolean if want
to execute one of the functions with no arguments passing.
So in the given example we need to specifiy a boolean argument for the Boolean object of non-primitive data type true or false.
public class File
{
public static void main(String[] args)
{
movie(true);
}
static void movie(Boolean...x) //Changed the parameter type to boolean from double
{
System.out.println("No varargs"+x);
}
static void movie(int...x)
{
System.out.println("One argument");
}
}
Here is what I know about overload resolution in java:
The process of compiler trying to resolve the method call from given
overloaded method definitions is called overload resolution. If the
compiler can not find the exact match it looks for the closest match
by using upcasts only (downcasts are never done).
Here is a class:
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(Object a){
System.out.println(10);
}
}
As expected the output is 10.
However if I change the class definition slightly and change the second overloaded method.
public class MyTest {
public static void main(String[] args) {
MyTest test = new MyTest();
Integer i = 9;
test.TestOverLoad(i);
}
void TestOverLoad(int a){
System.out.println(8);
}
void TestOverLoad(String a){
System.out.println(10);
}
}
The output is 8.
Here I am confused. If downcasting was never to be used, then why did 8 get printed at all? Why did compiler pick up the TestOverLoad method which takes int as an argument which is a downcast from Integer to int?
The compiler will consider not a downcast, but an unboxing conversion for overload resolution. Here, the Integer i will be unboxed to an int successfully. The String method isn't considered because an Integer cannot be widened to a String. The only possible overload is the one that considers unboxing, so 8 is printed.
The reason that the first code's output is 10 is that the compiler will consider a widening reference conversion (Integer to Object) over an unboxing conversion.
Section 15.12.2 of the JLS, when considering which methods are applicable, states:
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing [...]
In Java, resolving methods in case of method overloading is done with the following precedence:
1. Widening
2. Auto-boxing
3. Var-args
The java compiler thinks that widening a primitive parameter is more desirable than performing an auto-boxing operation.
In other words, as auto-boxing was introduced in Java 5, the compiler chooses the older style(widening) before it chooses the newer style(auto-boxing), keeping existing code more robust. Same is with var-args.
In your 1st code snippet, widening of reference variable occurs i.e, Integer to Object rather than un-boxing i.e, Integer to int. And in your 2nd snippet, widening cannot happen from Integer to String so unboxing happens.
Consider the below program which proves all the above statements:
class MethodOverloading {
static void go(Long x) {
System.out.print("Long ");
}
static void go(double x) {
System.out.print("double ");
}
static void go(Double x) {
System.out.print("Double ");
}
static void go(int x, int y) {
System.out.print("int,int ");
}
static void go(byte... x) {
System.out.print("byte... ");
}
static void go(Long x, Long y) {
System.out.print("Long,Long ");
}
static void go(long... x) {
System.out.print("long... ");
}
public static void main(String[] args) {
byte b = 5;
short s = 5;
long l = 5;
float f = 5.0f;
// widening beats autoboxing
go(b);
go(s);
go(l);
go(f);
// widening beats var-args
go(b, b);
// auto-boxing beats var-args
go(l, l);
}
}
The output is:
double double double double int,int Long,Long
Just for reference, here is my blog on method overloading in Java.
P.S: My answer is a modified version of an example given in SCJP.
widening beats boxing, boxing beats var-args. In your example, the widening cannot happen, so the boxing it's applied and Integer is unboxed. Nothing unordinary.
Actually in the second example no downcasting is occurred. There occurred the following thing -
1. Integer is unwrapped/unboxed to primitive type int.
2. Then the TestOverLoad(int a) method is called.
In main method you declare Integer like -
Integer i = 9;
Then call -
test.TestOverLoad(i);
Whereas, you have 2 overloaded version of TestOverLoad() -
TestOverLoad(int a);
TestOverLoad(String a);
Here the second overloaded version of TestOverLoad() takes completely different argument String. Thats why Integer i is unboxed to a primitive type int and after that the first overloaded version is called.
All objects in Java extend the class Object, including the class Integer. These two class have the following relationship: Integer "is a(n)" Object because Integer extends Object. In your first example, the method with Object parameter is used.
In the second example, no methods are found that accept an Integer. In this case Java uses what is called auto-unboxing to resolve the Integer wrapper class to a primitive int. Thus, the method with the int parameter is used.
While accepted answer of #rgettman leads to very right source, more precisely, §15.12.2.2 and §15.12.2.3 of the JLS Section 15.12.2 discuss the applicability, not the resolution - what the OP asked for. In the example the OP provided both testOverLoad methods are applicable, .i.e. will be successfully resolved in the absence of another one.
Instead, 15.12.2.5. Choosing the Most Specific Method discusses the resolution of the applicable methods.
It reads:
One applicable method m1 is more specific than another applicable
method m2, for an invocation with argument expressions e1, ..., ek, if
any of the following are true:
...
m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter
types T1, ..., Tn, the type Si is more specific than Ti for argument
ei for all i (1 ≤ i ≤ n, n = k).
So, in the first example, provided by OP, for parameter i of type Integer method testOverLoad(Object a) is more specific than testOverLoad(int a).
This is happening due to Widening and Narrowing Type casting
Widening means a small type can be accommodated in a larger type without any loss of information.
Widening Typecasting is automatic.
That means a byte value can be automatically casted to short, int, long or double.
byte->short->int->float->double
Widens from left to right.
Type Casting in Java
Hope this answers your question!
you can check with one more example :
public class HelloWorld {
void show(String c){
System.out.println("int double overloaded method");
}
void show(Object c){
System.out.println("double int overloaded method");
}
}
here the you will get : double int overloaded method
There seems to be a bug in the Java varargs implementation. Java can't distinguish the appropriate type when a method is overloaded with different types of vararg parameters.
It gives me an error The method ... is ambiguous for the type ...
Consider the following code:
public class Test
{
public static void main(String[] args) throws Throwable
{
doit(new int[]{1, 2}); // <- no problem
doit(new double[]{1.2, 2.2}); // <- no problem
doit(1.2f, 2.2f); // <- no problem
doit(1.2d, 2.2d); // <- no problem
doit(1, 2); // <- The method doit(double[]) is ambiguous for the type Test
}
public static void doit(double... ds)
{
System.out.println("doubles");
}
public static void doit(int... is)
{
System.out.println("ints");
}
}
the docs say: "Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called."
however they don't mention this error, and it's not the programmers that are finding it difficult, it's the compiler.
thoughts?
EDIT - Compiler: Sun jdk 1.6.0 u18
The problem is that it is ambiguous.
doIt(1, 2);
could be a call to doIt(int ...), or doIt(double ...). In the latter case, the integer literals will be promoted to double values.
I'm pretty sure that the Java spec says that this is an ambiguous construct, and the compiler is just following the rules laid down by the spec. (I'd have to research this further to be sure.)
EDIT - the relevant part of the JLS is "15.12.2.5 Choosing the Most Specific Method", but it is making my head hurt.
I think that the reasoning would be that void doIt(int[]) is not more specific (or vice versa) than void doIt(double[]) because int[] is not a subtype of double[] (and vice versa). Since the two overloads are equally specific, the call is ambiguous.
By contrast, void doItAgain(int) is more specific than void doItAgain(double) because int is a subtype of double according the the JLS. Hence, a call to doItAgain(42) is not ambiguous.
EDIT 2 - #finnw is right, it is a bug. Consider this part of 15.12.2.5 (edited to remove non-applicable cases):
One variable arity member method named m is more specific than another variable arity member method of the same name if:
One member method has n parameters and the other has k parameters, where n ≥ k. The types of the parameters of the first member method are T1, . . . , Tn-1 , Tn[], the types of the parameters of the other method are U1, . . . , Uk-1, Uk[]. Let Si = Ui, 1<=i<=k. Then:
for all j from 1 to k-1, Tj <: Sj, and,
for all j from k to n, Tj <: Sk
Apply this to the case where n = k = 1, and we see that doIt(int[]) is more specific than doIt(double[]).
In fact, there is a bug report for this and Sun acknowledges that it is indeed a bug, though they have prioritized it as "very low". The bug is now marked as Fixed in Java 7 (b123).
There is a discussion about this over at the Sun Forums.
No real resolution there, just resignation.
Varargs (and auto-boxing, which also leads to hard-to-follow behaviour, especially in combination with varargs) have been bolted on later in Java's life, and this is one area where it shows. So it is more a bug in the spec, than in the compiler.
At least, it makes for good(?) SCJP trick questions.
Interesting. Fortunately, there are a couple different ways to avoid this problem:
You can use the wrapper types instead in the method signatures:
public static void doit(Double... ds) {
for(Double currD : ds) {
System.out.println(currD);
}
}
public static void doit(Integer... is) {
for(Integer currI : is) {
System.out.println(currI);
}
}
Or, you can use generics:
public static <T> void doit(T... ts) {
for(T currT : ts) {
System.out.println(currT);
}
}
I'm having quite a tricky case here with generics and method overloading. Check out this example class:
public class Test {
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public void test() {
// This works perfectly. <T> is bound to String
// ambiguity between setValue(.., String) and setValue(.., Field)
// is impossible as String and Field are incompatible
Parameter<String> p1 = getP1();
Field<String> f1 = getF1();
setValue(p1, f1);
// This causes issues. <T> is bound to Object
// ambiguity between setValue(.., Object) and setValue(.., Field)
// is possible as Object and Field are compatible
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
setValue(p2, f2);
}
private Parameter<String> getP1() {...}
private Parameter<Object> getP2() {...}
private Field<String> getF1() {...}
private Field<Object> getF2() {...}
}
The above example compiles perfectly in Eclipse (Java 1.6), but not with the Ant javac command (or with the JDK's javac command), where I get this sort of error message on the second invocation of setValue:
reference to setValue is ambiguous,
both method
setValue(org.jooq.Parameter,T)
in Test and method
setValue(org.jooq.Parameter,org.jooq.Field)
in Test match
According to the specification and to my understanding of how the Java compiler works, the most specific method should always be chosen: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448
In any case, even if <T> is bound to Object, which makes both setValue methods acceptable candidates for invocation, the one with the Field parameter always seems to be more specific. And it works in Eclipse, just not with the JDK's compiler.
UPDATE:
Like this, it would work both in Eclipse and with the JDK compiler (with rawtypes warnings, of course). I understand, that the rules specified in the specs are quite special, when generics are involved. But I find this rather confusing:
public <T> void setValue(Parameter<T> parameter, Object value) {
}
// Here, it's easy to see that this method is more specific
public <T> void setValue(Parameter<T> parameter, Field value) {
}
UPDATE 2:
Even with generics, I can create this workaround where I avoid the type <T> being bound to Object at setValue invocation time, by adding an additional, unambiguous indirection called setValue0. This makes me think that the binding of T to Object is really what's causing all the trouble here:
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public <T> void setValue0(Parameter<T> parameter, Field<T> value) {
// This call wasn't ambiguous in Java 7
// It is now ambiguous in Java 8!
setValue(parameter, value);
}
public void test() {
Parameter<Object> p2 = p2();
Field<Object> f2 = f2();
setValue0(p2, f2);
}
Am I misunderstanding something here? Is there a known compiler bug related to this? Or is there a workaround/compiler setting to help me?
Follow-Up:
For those interested, I have filed a bug report both to Oracle and Eclipse. Oracle has accepted the bug, so far, Eclipse has analysed it and rejected it! It looks as though my intuition is right and this is a bug in javac
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7031404
https://bugs.eclipse.org/bugs/show_bug.cgi?id=340506
https://bugs.eclipse.org/bugs/show_bug.cgi?id=469014 (a new issue in Eclipse Mars)
JDK is right. The 2nd method is not more specific than the 1st. From JLS3#15.12.2.5
"The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error."
This is clearly not the case here. I emphasized any invocation. The property of one method being more specific than the other purely depends on the two methods themselves; it doesn't change per invocation.
Formal analysis on your problem: is m2 more specific than m1?
m1: <R> void setValue(Parameter<R> parameter, R value)
m2: <V> void setValue(Parameter<V> parameter, Field<V> value)
First, compiler needs to infer R from the initial constraints:
Parameter<V> << Parameter<R>
Field<V> << R
The result is R=V, per inference rules in 15.12.2.7
Now we substitute R and check subtype relations
Parameter<V> <: Parameter<V>
Field<V> <: V
The 2nd line does not hold, per subtyping rules in 4.10.2. So m2 is not more specific than m1.
V is not Object in this analysis; the analysis considers all possible values of V.
I would suggest to use different method names. Overloading is never a necessity.
This appears to be a significant bug in Eclipse. The spec quite clearly indicates that the type variables are not substituted in this step. Eclipse apparently does type variable substitution first, then check method specificity relation.
If such behavior is more "sensible" in some examples, it is not in other examples. Say,
m1: <T extends Object> void check(List<T> list, T obj) { print("1"); }
m2: <T extends Number> void check(List<T> list, T num) { print("2"); }
void test()
check( new ArrayList<Integer>(), new Integer(0) );
"Intuitively", and formally per spec, m2 is more specific than m1, and the test prints "2". However, if substitution T=Integer is done first, the two methods become identical!
for Update 2
m1: <R> void setValue(Parameter<R> parameter, R value)
m2: <V> void setValue(Parameter<V> parameter, Field<V> value)
m3: <T> void setValue2(Parameter<T> parameter, Field<T> value)
s4: setValue(parameter, value)
Here, m1 is not applicable for method invocation s4, so m2 is the only choice.
Per 15.12.2.2, to see if m1 is applicable for s4, first, type inference is carried out, to the conclusion that R=T; then we check Ai :< Si, which leads to Field<T> <: T, which is false.
This is consistent with the previous analysis - if m1 is applicable to s4, then any invocation handled by m2 (essentially same as s4) can be handled by m1, which means m2 would be more specific than m1, which is false.
in a parameterized type
Consider the following code
class PF<T>
{
public void setValue(Parameter<T> parameter, T value) {
}
public void setValue(Parameter<T> parameter, Field<T> value) {
}
}
void test()
PF<Object> pf2 = null;
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
pf2.setValue(p2,f2);
This compiles without problem. Per 4.5.2, the types of the methods in PF<Object> are methods in PF<T> with substitution T=Object. That is, the methods of pf2 are
public void setValue(Parameter<Object> parameter, Object value)
public void setValue(Parameter<Object> parameter, Field<Object> value)
The 2nd method is more specific than the 1st.
My guess is that the compiler is doing an method overloading resolution as per JLS, Section 15.12.2.5.
For this Section, the compiler uses strong subtyping (thus not allowing any unchecked conversion), so, T value becomes Object value and Field<T> value becomes Field<Object> value. The following rules will apply:
The method m is applicable by
subtyping if and only if both of the
following conditions hold:
* For 1in, either:
o Ai is a subtype (§4.10) of Si (Ai <: Si) or
o Ai is convertible to some type *Ci* by unchecked conversion
(§5.1.9), and Ci <: Si.
* If m is a generic method as described above then Ul <: Bl[R1 = U1,
..., Rp = Up], 1lp.
(Refer to bullet 2). Since Field<Object> is a subtype of Object then the most specific method is found. Field f2 matches both methods of yours (because of bullet 2 above) and makes it ambiguous.
For String and Field<String>, there is no subtype relationship between the two.
PS. This is my understanding of things, don't quote it as kosher.
Edit: This answer is wrong. Take a look at accepted answer.
I think the issue comes down this: compiler does not see the type of f2 (i.e. Field) and the inferred type of formal parameter (i.e. Field -> Field) as the same type.
In other words, it looks like type of f2 (Field) is considered to be a subtype of the type of formal parameter Field (Field). Since Field is at the same type a subtype of Object, compiler cannot pick one method over another.
Edit: Let me expand my statement a bit
Both methods are applicable and it looks like the Phase 1: Identify Matching Arity Methods Applicable by Subtyping is used to decide which method to call and than rules from Choosing the Most Specific Method applied, but failed for some reason to pick second method over first one.
Phase 1 section uses this notation: X <: S (X is subtype of S). Based on my understanding of <:, X <: X is a valid expression, i.e. the <: is not strict and includes the type itself (X is subtype of X) in this context. This explains the result of Phase 1: both methods are picked as candidates, since Field<Object> <: Object and Field<Object> <: Field<Object>.
Choosing the Most Specific Method section uses same notation to say that one method is more specific than another. The interesting part the paragraph that starts with "One fixed-arity member method named m is more specific than another member...". It has, among other things:
For all j from 1 to n, Tj <: Sj.
This makes me think that in our case second method must be chosen over the first one, because following holds:
Parameter<Object> <: Parameter<Object>
Field<Object> <: Object
while the other way around does not hold due to Object <: Field<Object> being false (Object is not a subtype of Field).
Note: In case of String examples, Phase 1 will simply pick the only method applicable: the second one.
So, to answer your questions: I think this is a bug in compiler implementation. Eclipse has it is own incremental compiler which does not have this bug it seems.