Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The method ambiguous for the type - Why not resolving

Tags:

java

public class Animal {}

public class Bird extends Animal {}

public class Mamal extends Animal {}

public class Human extends Mamal {}

public class Main {

    public void Hungry(Mamal mamal){
        System.out.println("Mammal");
    }   
    public void Hungry(Human human){
        System.out.println("Human");        
    }
    public void Hungry(Bird bird){
        System.out.println("Bird");
    }
    public static void main(String a[]){
        Main main = new Main();
        main.Hungry(null);
}

Compiler says The method Hungry(Mamal) is ambiguous. I would expect to execute the "Human" method as it is the lowest level. I failed to find the reason for ambiguity from http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12

like image 606
Kasun Avatar asked Mar 01 '14 20:03

Kasun


3 Answers

Human and Bird are at the same level in the inheritance hierarchy (not visually though). Or think of them as completely unrelated reference types. Therefore one isn't more specific than the other.

If you remove the Hungry(Bird) method, your code will compile.

The rules for more specific are here.

One fixed-arity member method named m is more specific than another member method of the same name and arity if all of the following conditions hold:

  • The declared types of the parameters of the first member method are T1, ..., Tn.

  • The declared types of the parameters of the other method are U1, ..., Un.

  • If the second method is generic, then let R1 ... Rp (p ≥ 1) be its type parameters, let Bl be the declared bound of Rl (1 ≤ l ≤ p), let A1 ... Ap be the type arguments inferred (§15.12.2.7) for this invocation under the initial constraints Ti << Ui (1 ≤ i ≤ n), and let Si = Ui[R1=A1,...,Rp=Ap] (1 ≤ i ≤ n).

  • Otherwise, let Si = Ui (1 ≤ i ≤ n).

  • For all j from 1 to n, Tj <: Sj.

  • If the second method is a generic method as described above, then Al <: Bl[R1=A1,...,Rp=Ap] (1 ≤ l ≤ p).

So you have

public void Hungry(Human human){
    System.out.println("Human");        
}
public void Hungry(Bird bird){
    System.out.println("Bird");
}

So Human is T1 and Bird is U1 (the reverse is also attempted). Methods are not generic.

S1 = U1

For all j from i to n (1 to 1), this should hold: Ti <: Si, where <: is

We write T <: S to indicate that that the subtype relation holds between types T and S.

This doesn't hold for our two methods as Human is not a sub type of Bird and vice versa, so there is no more specific method to call, ie. ambiguity.

It's the same as if you had

void method(String s){}
void method(RandomReferenceType t) {}

and tried to call

method(null);
like image 148
Sotirios Delimanolis Avatar answered Sep 19 '22 13:09

Sotirios Delimanolis


The amibuity is because you have three methods with same name and you are passing a null value. The compiler doesn't know which method you are calling. Just write one ie public void hungry(Animal animal) and check the type of the animal inside. For example if(animal instanceof Bird) { System.out.println("Bird") ..... Also change the method names to lowercase. Sometimes the compiler will fail.

like image 33
Sergi Avatar answered Sep 18 '22 13:09

Sergi


Since null does not have a type associated with it, the compiler does not know which of your hungry methods should be invoked; therefore, it's "ambiguous". To disambiguate it, simply cast it:

public class Main {

    public void hungry(Mamal mamal){
        System.out.println("Mammal");
    }   
    public void hungry(Human human){
        System.out.println("Human");        
    }
    public void hungry(Bird bird){
        System.out.println("Bird");
    }
    public static void main(String a[]){
        Main main = new Main();
        main.hungry((Mamal)null);
    }
}

class Animal {}
class Bird extends Animal {}
class Mamal extends Animal {}
class Human extends Mamal {}
like image 23
Jan Nielsen Avatar answered Sep 22 '22 13:09

Jan Nielsen