How does Java handle potentially ambiguous method calls? - java

Playing around with ambiguous methods calls that have multiple parameters, I noticed that quite often it was not actually ambiguous when I expected it to be, and this led to some strange behavior that I couldn't quite understand.
For example, with the following inheritance structure:
public static class A {
}
public static class B extends A {
}
public static class C extends B {
}
And running the method test().
public static void test() {
test(new C(), new C(), new C());
}
For some reason these two methods are ambiguous
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, C xx, A xxx) {
System.out.println("TEST 2");
}
However swapping the last two arguments in the second method makes that one take priority.
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, A xx, C xxx) {
System.out.println("TEST 2"); //No longer ambiguous, this one is called
}
Can someone please explain this behavior, and also in general exactly how quasi-ambiguous method calls are determined in Java with multiple parameters?

Reading through the Java Language Specifications chapter on choosing the most specific method, the following statements are important to note:
One applicable method m1 is more specific than another applicable
method m2, for an invocation with argument expressions e1, ..., ek,
if ...
...m2 is not generic, and 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).
What this basically means is that given two (non varargs) method signatures that can match a method call, the compiler will choose the more specific method, and the more specific method is the one where each parameter is more specific than (i.e. either the same class as or a subclass of) the corresponding parameter in the other signature (ignoring generics here for the sake of simplicity).
So, for example when you have (A,A,B) and (A,A,C), the latter is more specific because A = A and C is a subclass of B, so the choice is clear and unambiguous.
But when you have (A,A,B) and (A,C,A), the former can't be more specific because C is a subclass of A, but the latter can't be more specific either because B is a subclass of A. Hence, ambiguity.

Its because both of test methods can accept instances of C as its arguments as C can act as B and A

public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, C xx, A xxx) {
System.out.println("TEST 2");
}
The problem here is that both methods apply to (A, C, B). In this specific circumstance ambiguity is present.
With the unambiguous example you provided there is no signature common to both declarations:
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, A xx, C xxx) {
System.out.println("TEST 2"); //No longer ambiguous, this one is called
}
The first applies to (A, A, B), the second applies to (A, A, C). The second is merely overriding the former in providing a more specific use case (signature). You might want to consider it as overriding the former, although that probably isn't the technical term.
By extension C is a A so given the choice of calling methods where the parameter is C or A the interpreter will call either (hence ambiguity can arise) but must call the one with the more specific parameter, if available. This can be described as polymorphism; the run time type of the instance is used to determine the class and method calls are searched from the descended class up.
As JB Nizet points out, the language specs are the authority here, but I like to experiment too.

I try to explain you what would be the problem.
For instance I have a class that contains three methods that with different parameters calculates the multiplication of two numbers.
These methods are:
long mul(int x, long y)
long mul(long x, int y)
long mul(long x, long y)
Because the overloading all these methods are valid and calculate the same thing: the result of the multiplication beetween x and y.
Suppose to have two variables which are the parameters for the method:
int x;
long y;
If I call mul(x,y) then I will get x*y as result because mul(int, long) is the most
specific method for these parameters.
If I call mul((long) x, y) then I will get again x*y because mul(long, long) is the most specific method for these parameters.
Instead if I call mul(x, x) I wont' get x*x because the language (Java) can't guess what is the best casting for the parameters.
Calling mul(x, x) leads to this dilemma: I should cast x to long, so calling mul(long ,long) or I should cast y to int, so calling mul(int, int).
This is the problem that you can find while using overloading.
I hope I help you!

Related

Lambda expression using interface in one line

I'm learning about interfaces and I faced a problem which I cannot understand. It's about lambda expression which I learn that can be used in one line, but I've create a case, where this expression does not working and I don't know where I've made a mistake.
I have defined this interface:
public interface MathOperations {
int add(int a, int b);
}
Next I have defined class in which I want to test this interface with adder method.
public class App {
public static void main(String[] args) {
int x;
x = adder((a, b) -> return a+b);
}
public static int adder(MathOperations mo){
return mo.add(3, 5);
}
}
Unfortunately the line with the x assignment doesn't work and I cannot figure out where I've made a mistake. The compiler does not recognize the a and b variable in the return statement. I know that I can make this assignment with brackets but I'm curious if I can do this in one line.
#FunctionalInterface
interface MathOperations {
int add(int a, int b);
}
Here are two ways to do what you want.
To create a lambda, you need to specify the interface type and provide the definition of what to do with a and b.
then you can invoke the lambda and get the value.
MathOperations compute = (a,b)->a+b;
x = compute.add(2,3);
System.out.println(x);
The above does essentially the following behind the scenes.
Here an anonymous class is defined using the interface and instantiated using the new keyword. (the class contains the implemented method).
Implementing the interface was standard until the concept of FuntionalInterfaces and lambdas were introduced in Java 8.
Then call the adder method supplying the instance mo just created or call the method with the previously created compute lambda.
MathOperations mo =new MathOperations() {
public int add(int a,int b) {
return a+b;
}};
System.out.println(adder(mo));
System.out.println(adder(compute));
output of above three print statements
5
8
8
public static int adder(MathOperations mo){
return mo.add(3, 5);
}
Note: Imo, a more versatile interface can be created by following examples from the API functional interfaces already defined. The name MathOperation is fine but the add method is too specific (and functional interfaces may only contain one abstract method). So instead of having an add method, have a compute or similar method and let the name of the lambda dictate its operation.
MathOperation add = (a,b)->a+b;
int sum = add.compute(10,20); // 30
MathOperation sub = (a,b)->a-b;
int diff = sub.compute(10,20) // -10

How does a polymorphic instance select its methods?

I have problems understanding the behaviour of this piece of code.
a is defined as an A, c is defined as a C.
Then, at the end of the public class, a = c.
When a calls the display() method it reaches the C version of it.
But when a calls the f() it only reaches the A version, despite the fact that the first arguments (byte and long) are more compliant with long than float.
It's an exercice from a book, but explanation is scarce, or inexistent.
class A{
public void display(){
System.out.println("I am an A ");
}
public void f(double x){
System.out.println("A.f(double = " + x + ") ");
}
}
class C extends A{
public void display(){
System.out.println("I am a C ");}
public void f(long q){
System.out.println("C.f(long = " + q + ") ");}
}
public class PolySurStack{
public static void main(String Args[]){
byte bb =1; long q = 4; float x = 5.f;
System.out.println(" ** A **");
A a = new A(); a.display();
a.f(bb); a.f(x);
System.out.println();
System.out.println(" ** C **");
C c = new C(); c.display();
c.f(bb); c.f(q); c.f(x);
System.out.println();
a = c; a.display();
a.f(bb); a.f(q); a.f(x);
}
}
When you call a.f(bb) or a.f(q) or a.f(x), the only method signatures the compiler can choose from are those defined in class A (or any super class of A), since a is a reference variable of type A.
Therefore, only public void f(double x) is considered. In order for public void f(long q) to be a candidate for overload resolution, you'd have to cast a to type C before calling f(), since only class C defines a method with that signature.
The important thing to understand is that method overloading resolution takes place in compile time. Only the compile time type of the reference variable for which you call the method determines which method signatures are candidates for method overloading resolution, as well as which candidate will be chosen.
I just found this on another forum :
Overloading :(same function name but different signature)
Two or more methods having the same name with different arugment in same class is known as Overloading.
Overloading is used when you want to extend the functionality.
Overloading is known as compile time polymorphism
Overriding :(same function name but same signature)
Two or more methods having the same method name and same arugment in parent class and child class in known as overriding.
Overriding is used when you want to reuse the existing functionlity.
Overriding is known as run time polymorphism
So the answer to my question seems to be that overriding resolution (like for display() )occurs at run time (here after a = c) while overloading resolution (like for f() ) occurs at compilation time, when a is Still an A.
I think.
I also found this page : https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/
to be clear and highly relevant to this topic.
The method selected by the compiler depends on the declared type, not on the runtime type.
The first series that declares as variable A can only invoke A methods (whatever the runtime type instantiated as A derives only of Object) :
A a = new A();
a.f(bb); a.f(x);
For the second series, the compiler binds the methods with the most specific parameter matching to the invocation since C is a A and so the compiler can bind any public methods of these here :
C c = new C();
c.f(bb); c.f(q); c.f(x);
But in the last chunk of code that probably questions yourself, a refers to C as runtime object but to A as declared type :
A a = new A();
// ...
a = c;
a.f(bb); a.f(q); a.f(x);
So only methods defined in A may be invoked.
I'll try to clarify the answer of #eran a bit so you can understand it.
A subclass has all the methods of its superclass, and then perhaps some more in addition to them. You have a variable of type A, in which you store an object of type C. C has all the methods that are defined in class A, and also an additional method that is f(long q). A is unaware of this new method, so since you store the object in a variable of A, you can't call f(long q).
You can however call display() because it is defined in A, but it will still be the C object that executes it.

What is the basic concept of overloading a method

In overloading when we overload a method why we cant make a new method which works same as overloaded method because we have to write the same number of line of code Such as in my example...why i cant make a new method b() which multiply two numbers.
public class que {
public void a(int a)
{
System.out.println(a);
}
public void a(int b,int c) {
System.out.println(b*c);
}
public static void main(String[] args) {
que queObject = new que();
queObject.a(5);
queObject.a(3,4);
}
}
You can make all your methods have different names. The point is you don't have to. This reduces the number of names a developer using the API needs to learn.
e.g. in the PrintWriter you have lots of methods called print and println which conceptually all do the same thing. They could have been given different names, but then you would need to know which method you wanted to call,
At runtime, each method signature is unique as it includes the return type and the non generic argument types form. i.e. in byte code the names are made unique for you.
In Java, a method cannot be distinguished/overloaded by it's return type, though in Java 6 there was a bug which allowed overloading on methods with different return types.
Nobody says you can't do this. It just isn't method overloading. That's defined as two or more methods of the same name, but with different (parameter) signatures.
method name signifies what a method does. so if you have 2 methods having same name but expects different arguments. its beneficial for the understanding of code and better design to have the same name.
so if you add another method
public void a(int b,int c,int d) {
System.out.println(b*c*d);
}
you basically doing the same behaviour i.e. multiplication but with more arguments. so overriding is better for understanding and good coding principles.
Consider This
public void eat(Orange o) {
// eat Orange
}
public void eat(Mango m) {
// eat Mango
}
You want different implementation on the basis of what you pass as a parameter but want to keep method name same.
For More Info --> Polymorphism vs Overriding vs Overloading
Here's my explanation:
public class Calculator {
// used for integer numbers
public int sum(int a, int b) {
return a + b;
}
// used for double numbers
public double sum(double a, double b) {
return a + b;
}
}
In this case you don't care if you use sum method with int or double - sum method is overloaded, so it will take both int and doubles. It's much easier than using sumInts() and sumDoubles() separately.
Method overloading is when, in a class, there are more than one method with same name but different arguments although it can have different return types (different return types is in itself is not a distinguishing feature and if only that is changed will result in a compile error).
For a complete discussion, see: http://beginnersbook.com/2013/03/polymorphism-in-java/
Why do we need it?
An example will be enlightening: Lets take the ubiquitous StringBuilder class and its append methods. They are a prime example of overloading. A specific instance of method overloading is constructor overloading as well. See the StringBuilder again: http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html.
As another example suitable to your case: we can have an appendBoolean(boolean b) and a appendString(String b) and a appendChar(char c) in the StringBuilder class as well. It is a matter of clarity and choice to either have that or just have a set of overloaded append methods. To me - since the operation is to append but we are appending different instance types - having an overloaded append makes sense and provides clarity and is concise. On the other hand, you have no such choice for overloaded constructors: they need to have the same name as the class - that is by convention and by design :-)

Is this Overloading, methods with same name in different classes and different signature?

If I have the following code in Java:
class A {
public int add(int a , int b) {
return (a+b);
}
}
class B extends A {
public float add(float a , float b) {
return (a+b);
}
In this particular case the sub-class isn't exactly overriding the base class's add function as they have different signatures and the concept of overloading occurs only if they are in the same scope. So, is the function add(float , float) in the sub-class B treated as an entirely new function and the concept of overloading and overriding is not applicable to it? And does it use 'Static binding' or 'Dynamic Binding'?
Method add in class b is an overload of add in class a. Not an override. An override would just be a different implementation of the original add method.
In brief, yes. To override, you need to replicate the complete method signature, which includes the method name, parameters and return types. From the tutorial
An instance method in a subclass with the same signature (name, plus
the number and the type of its parameters) and return type as an
instance method in the superclass overrides the superclass's method.
You might want to consider the #Override annotation, which will trigger a compiler error if you don't successfully overrride a method.
In this particular instance, it perhaps looks like you don't need overriding so much as some solution including generics. So you could instantiate a class a<Integer> and a similar class a<Float>
In that case you are not overriding the method, since the signatures are different.
But there is overloading in class b, since you have two methods with the same name but different parameters (one if class a, and the other one in class b)
Hope it helps.
There can be a method that is not overridden but overloaded in the subclass. Here the subclass has two add() methods. The version which accepts int arguments(not overridden), and the overloaded method add() which accepts float arguments.
I think in this particular case neither overloading nor overriding occurs, because return type must be same in case overloading and overriding, so neither static binding nor dynamic binding happens in this case.
method overloading is not possible in case of different return type, because compiler can't figure that which method he need to call.
I know it's late answer but i think it's important question need to be answered for beginners.
One key point in overloading is it works in inheritance.
Next is either it's Static binding or Dynamic binding.
It is Static Binding So, why?
Static Binding
Static binding in Java occurs during Compile time.
private, final and static methods and variables uses static binding and bonded by compiler.
Static binding uses Type (class in Java) information for binding.
Dynamic Binding
Dynamic binding occurs during Runtime.
Dynamic methods bonded during runtime based upon runtime object.
Dynamic binding uses Object to resolve binding.
But the important part is here
Overloaded methods are bonded using static binding while overridden methods are bonded using dynamic binding at runtime.
Java compiler determines correct version of the overloaded method to be executed at compile time based upon the type of argument used to call the method and parameters of the overloaded methods of both these classes receive the values of arguments used in call and executes the overloaded method.
B a=new B();
a.add(4, 5);
a.add(4.0f, 5.0f);
So if you will create reference of type B then it will search for proper argument type
and for above code it will execute both methods.
A a=new B();
a.add(4, 5);
a.add(4.0f, 5.0f);
but for above code it will give compile time error for float arguments.
Hope it clears all doubts.
First things first
Is it method overriding ?
No , since to override a method you need to replicate the complete method signature as pointed out in Brian Agnew's answer and as I explain below.
Is it overloading ?
Yes , Method "add" has an overloaded implementation in Class B.
Consider the following code:
class C{
public static void main(String args[]){
B a = new B();
a.add(2 , 3);
a.add(2.0 , 3.0);
}
}
class A {
public int add(int a , int b) {
System.out.print("INT ");
return a + b;
}
}
class B extends A {
public double add(double a , double b) {
System.out.print("Double ");
return a + b;
}
}
OUTPUT : INT Double
So , the method in Class B in your code overloads the add method that it inherits from its parent
Does it use Static Binding or Dynamic Binding ?
This is what makes me conclude that OP is confused.It is static binding because it is a overloaded function. The only way to think of dynamic binding would have been in below scenario
class C{
public static void main(String args[]){
A a = new B();
a.add(2.0 , 3.0);
}
}
class A {
public int add(int a , int b) {
System.out.println("A : INT");
return a + b;
}
}
class B extends A {
public int add(int a , int b) {
System.out.println("B : INT");
return a + b;
}
public double add(double a , double b) {
System.out.println("Double");
return a + b;
}
}
Output : B : INT
Here , the parent class A has a contract that says , "I have an add behaviour for ints" . class B inherits this add behaviour and makes it more specific and at the same time also provides a new behaviour where it can add doubles.
But class A has "no knowledge of this behaviour".
So an object of class A "cannot" add doubles. To do that you need a more specific type of A object i.e. a B object.
The method add() in class A is also available to class B by inheritance, therefore the method is overloaded in class by changing the data type from int, int to float, float.
The concept of Overloading comes in play if and only if the functions are in the same scope or class.
cz if this is the case of method overloading then for same method signature or same argument type the compiler gets confuse and must give compile time error .
but in the above program in class B if you pass the same argument in same order then according to overloading it must give error but it is not happening u can check it i already have.
It is the case of inheritance where through object reference if you call any method then the compiler will check it in child class ,if its not there then it will look into parent class that the above program is all about.
hope this is helpfull.

Java overloading and inheritance rules

I've been studying because I have an exam and I don't have many problems with most of Java but I stumbled upon a rule I can't explain. Here's a code fragment:
public class A {
public int method(Object o) {
return 1;
}
public int method(A a) {
return 2;
}
}
public class AX extends A {
public int method(A a) {
return 3;
}
public int method(AX ax) {
return 4;
}
}
public static void main(String[] args) {
Object o = new A();
A a1 = new A();
A a2 = new AX();
AX ax = new AX();
System.out.println(a1.method(o));
System.out.println(a2.method(a1));
System.out.println(a2.method(o));
System.out.println(a2.method(ax));
}
This returns:
1
3
1
3
While I would expect it to return:
1
3
1
4
Why is it that the type of a2 determines which method is called in AX?
I've been reading on overloading rules and inheritance but this seems obscure enough that I haven't been able to find the exact rule. Any help would be greatly appreciated.
The behavior of these method calls is dictated and described by the Java Language Specification (reference section 8.4.9).
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).
In your example, the Java compiler determines the closest match on the compile type of the instance you are invoking your method on. In this case:
A.method(AX)
The closest method is from type A, with signature A.method(A). At runtime, dynamic dispatch is performed on the actual type of A (which is an instance of AX), and hence this is the method that is actually called:
AX.method(A)
I will clarified it in more simple way. See when you making sub class object with super class reference like here you did.
Always one thing keep in your mind that when you call with super class reference, no matters object is of sub class it will go to the super class, check method with this name along with proper signature is there or not.
now if it will find it, than it will check whether it is overridden?? if yes than it will go to the sub class method like here it went. another wise it will execute the same super class method.
I can give you the example of it...just hide
public int method(A a) {
return 3;
}
method & check your answer you will get 1 2 1 2, why because it gives first priority to reference. because you overridden it & than calling it, so its giving 3..!! hope its big but easy to understand. Happy Learning
a2 referenced as an A and the JVM using the reference first (not the acutal object as you expected).

Categories

Resources