I have the following methods:
static void f(double x)
{
System.out.println("f(double)");
}
static void f(Double xObj)
{
System.out.println("f(Double)");
}
static void f(double... s)
{
System.out.println("f(double...)");
}
public static void main(String[] args)
{
double x1 = 8.5;
Double xO1 = 5.25;
f(x1);
f(xO1);
}
Output:
f(double)
f(Double)
The rule of searching an overloaded method is the following:
Search for the overloaded method without including method with auto (un)boxing and method with ellipsis.
If no method is found, search again with including method with auto (un)boxing.
If no method is found, search again with including method with ellipsis.
This rule is applicable when calling method f with primitive parameter, but when calling with auto boxing parameter this rule is not applicable.
Can anyone explain me if this rule is correct or not ? and what is the correct one ?
Thanks for advance :)
Java picks the most specific method that fits the arguments using this rule
"This rule is applicable when calling method f with primitive parameter, but when calling with auto boxing parameter this rule is not applicable."
When you remove the method f(Double), f(xO1) will call f(double) because that was the only, and the most specific method that fits the arguments.
For reference you may check the Java Language Specification
Related
Lets suppose I have a ComponentBase class, who is child of ObjectContextDecorator and grandchild of ObjectContext.
public class ComponentBase extends ObjectContextDecorator {
}
public class ObjectContextDecorator extends ObjectContext {
public void set(String objectTypePath, String characteristicName, Object value) {
//...
}
}
public class ObjectContext {
public void set(String characteristicName, Object value, boolean forced) {
//...
}
}
The set methods on ObjectContextDecorator and ObjectContext are very simillar. Consider this sample code:
ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);
Both methods' signatures fit the one being called correctly. I am not able to change the methods' signatures since it is not my code.
How does the compiler know which method I intended to call?
I know that on the IDE you can point out which method you are actually intending to call, but in this situation, I am using a class loader to load a class which has a method containing the sample code.
It's all explained in the JLS §15.2 Method Invocation Expressions. It tells you all about how the correct method to call is chosen. And note that this does not always succeed.
In your specific case, the two methods are overloads of each other, so §15.2.2 "Compile-Time Step 2: Determine Method Signature" applies - which overload to call is determined at compile time. This step is further split into 3 phases.
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.
In the first phase, the compiler tries to find applicable methods without allowing boxing conversions. In your case, to call the overload that takes an Object, a boxing conversion is needed to convert the boolean true to the type Object, so that overload won't be chosen in the first phase.
If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (§15.12.2.3).
Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by strict invocation.
Well, we have found exactly one method, so we will just choose that method. There is no ambiguity.
How does the compiler know which method I intended to call?
It checks for the arguments and determines which one is more specific following the rules described JLS §15.2
In your case, the call:
base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)
the arguments are String,String, boolean
Which matches the first class (parameters names changed for brevity)
public class ObjectContext {
public void set(String s, Object o, boolean b){
//...
}
}
The second class is not invoked because the third parameter is an Object:
public class ObjectContextDecorator extends ObjectContext {
public void set(String s, String ss, Object thisOneRightHere) {
//...
}
}
and while the boolean value true can match if it is autoboxed still the first one is more specific. The rule that is applying here is:
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion
But, for instance, if you use the object wrapper Boolean in the signature:
public class ObjectContext {
public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
//...
}
}
Then they will both match, and the compiler would let you know with the following message:
> A.java:25: error: reference to set is ambiguous
> base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
> ^ both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match
But that's not the case in your example.
Primitives are at it again, breaking rules, I learned before. Well not technically primitive but composed of them.
I learned that whenever there's no method more specific than rest, compile time error occurs as it happens here.
public static void caller(){
z5(); // Error. Neither Integer, nor String is more specific
z5(null); // Error for the same reason
}
public static void z5(Integer...integers){
System.out.println("Integer z5 called");
}
public static void z5(String...strings){
System.out.println("String z5 called");
}
Now comes primitives into the picture.
public static void caller(){
z1(null); // Error cuz [I, [J, [F all are subclass of Object.
z1(); // SURPRISINGLY works and calls the int one. WHY?
}
public static void z1(int...integers){
System.out.println("int z1 called");
}
public static void z1(long...longs){
System.out.println("long z1 called");
}
public static void z1(float...floats){
System.out.println("float z1 called");
}
Expected compile time errors occurs here.
public static void caller(){
z1(null); // Error
z1(); // Error
}
public static void z1(int...integers){
System.out.println("int z1 called");
}
public static void z1(boolean...bools){
System.out.println("bool z1 called");
}
Now my question is, int[], float[], or any array of primitives are not primitive types then Why are they treated differently than other reference types?
--UPDATE--
#john16384 You don't think I read your "Possible duplicate" Varargs in method overloading in Java
Top answer there says You cannot combine var-args, with either widening or boxing. Besides I forgot to mention, OP's code posted there, works fine on my jdk 7.
What exactly is going on which works for (int...is) & (float...fs) but not for (Integer...is) & (Float...fs) and not for (int...is) & (boolean...bool)
Quote from the JLS about varargs invocations when multiple methods are applicable:
15.12.2.5. Choosing the Most Specific Method
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
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. In cases such as an
explicitly typed lambda expression argument (§15.27.1) or a variable
arity invocation (§15.12.2.4), some flexibility is allowed to adapt
one signature to the other.
The important part here is how methods are defined to be more specific. It basically says that int... is more specific than long... because any values you could pass to the first method could also be passed to the second method.
This will also apply to the case where you pass no arguments. int... will be the most specific (it will even see byte... as more specific!).
public static void main(String[] args) {
bla();
}
private static void bla(long... x) {}
private static void bla(int... x) {}
private static void bla(short... x) {}
private static void bla(byte... x) {} // <-- calls this one
The reason you get an error when also creating an overload boolean... is that it now is ambigious which one to call, and the compiler stops before getting to the point where it has to pick the most specific method.
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...
So I have the following overloaded methods:
private static void foo(short... a)
{
System.out.println("Calling var-len");
}
private static void foo(int a, int b)
{
System.out.println("Calling int-int");
}
private static void foo(int a, double b) //(3)
{
System.out.println("Calling int-double");
}
private static void main (String[] args)
{
foo((short)2, (short)5); //This one outputs "Calling int-int"
}
I know that variable arity method has the lowest priority during method resolution phases, so in this case if I call foo((short)2, (short)4); I would get "Calling int-int".
HOWEVER, if I change method (3) to foo(short a, double b), the variable arity method is picked! (Java 7).
Could anyone explain this?
According to the specification:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2
"However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase."
Your question is a typical example for numerical promotion in java. It tries to resolve for the exact signature match (short, short), but in your case you don't have that method. Java checks for subsequent compatible data type (say int), it promotes both short to int data types and tries to find a match, it finds it.
If none of the numeric promotion works, it will resolve to variable argument method in your code.
Please read on numeric promotions on below link..
http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
class WrongOverloading{
void something(String [] a){ .. }
Integer something(String... aaa){ return 1;}
}
Above code does not compile! Compiler says these are duplicate methods.
So using String array or String var-args exactly mean the same?
How are they implemented internally?
They are effectively the same, except the compiler will not accept an varargs unless its the last argument and it won't allow you to pass multiple arguments to an array.
public void methodA(int... ints, int a); // doesn't compile
public void methodA(int[] ints, int a); // compiles
public void methodB(int... ints); // compiles
public void methodC(int[] ints); // compiles
methodB(1); // compiles
methodB(1,2,3,4); // compiles
methodC(1); // doesn't compile
methodC(1,2,3,4); // doesn't compile
From this SO discussion
The underlying type of a variadic method function(Object... args) is
function(Object[] args). Sun added varargs in this manner to preserve
backwards compatibility.
So, as every other answer has said, yes, they're the same.
String... aaa is just like having String[] aaa.
I am assuming that the semicolon after the second function is a typo...
Yes, it's the same.
You can read this article:
It is still true that multiple arguments must be passed in an array, but the varargs feature automates and hides the process.
yes, they are the same because when you call method with elipsis (String...) it converts to String array.
The compiler behind the scenes actually converts your var args method to a method with an array input.
This is the reason why you can have a var args method overloaded with an array as input because after compilation both of them will be identical.
Yes, both are the same ...
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html Just read this site, you will come to know
The [vararg] attribute specifies that the method takes a variable number of parameters. To accomplish this, the last parameter must be a safe array of VARIANT type that contains all the remaining parameters :
[vararg [, optional-attributes]] return-type function-name(
[optional-param-attributes] param-list,
SAFEARRAY(VARIANT) last-param-name);
The varargs syntax basically lets you specify that there are possible parameters, right? They can be there, or cannot be there. That's the purpose of the three dots. When you call the method, you can call it with or without those parameters. This was done to avoid having to pass arrays to the methods.
Have a look at this:
See When do you use varargs in Java?
final public class Main
{
private void show(int []a)
{
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+"\t");
}
}
private void show(Object...a)
{
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+"\t");
}
System.out.println("\nvarargs called");
}
public static void main(String... args)
{
int[]temp=new int[]{1,2,3,4};
Main main=new Main();
main.show(temp);
main.show(); //<-- This is possible.
}
}
It's for this reason, varargs is basically not recommended in overloading of methods.
System.out.printf(); is an example of varargs and defined as follows.
public PrintStream printf(String format, Object ... args)
{
return format(format, args);
}
format - A format string as described in Format string syntax
args - Arguments referenced by the format specifiers in the format string. If there are more arguments than format specifiers, the extra arguments are ignored. The number of arguments is variable and may be zero. The maximum number of arguments is limited by the maximum dimension of a Java array as defined by the Java Virtual Machine Specification. The behaviour on a null argument depends on the conversion.
while calling a method it doesnt care about the return type it will consider the method name , number of parameters and type of parameters and order of parameters .here you are specifying a method with same name same parameters .bcoz in case of var arg if we call method with 2 parameters same method will be executed , if we call method with 3 parameters it will call same method .
here , if we call something(String [] a) and something(String... aaa) same method will be called .bcoz we can replace array with var-arg then a confusion will be arise wich method should be called. then method ambiguity will occour . thats why its showing duplicate method.
here if we pass array to var - arg parameter method it will be executed.internally it converts var - args to single dimensional array.