简体   繁体   中英

Java ambiguous method call with generics

Java generics ambiguous method call in the following example:

public class Foo {

    public <Y, X extends Y> void set(Path<Y> attribute, X value) {
        ...
    }

    public <Y> void set(Path<Y> attribute, Expression<? extends Y> value) {
        ...
    }
}

Try to invoke the 2nd method

    Foo foo = new Foo();
    Path<Object> path = new Path<Object>();
    foo.set(path, new Expression<Object>(value));

Inside Eclipse, no error. But on command line, compiling error:

error: reference to set is ambiguous
                foo.set(path, new Expression<Object>(value));
                       ^
  both method <Y#1,X>set(Path<Y#1>,X) in Foo and method <Y#2>set(Path<Y#2>,Expression<? extends Y#2>) in Foo match
  where Y#1,X,T,Y#2 are type-variables:
    Y#1 extends Object declared in method <Y#1,X>set(Path<Y#1>,X)
    X extends Y#1 declared in method <Y#1,X>set(Path<Y#1>,X)
    T extends Object declared in class Foo
    Y#2 extends Object declared in method <Y#2>set(Path<Y#2>,Expression<? extends Y#2>)

How to invoke the 2nd method?

There is not way to force the compiler to choose either version of the method. As stated in comments it would be wise to consider to simply call both method differently.

Perhaps you should consider to define a single method instead that follows the more complex Expression approach and when necessary define expressions that simply return a given constant value.

I think you should consider to use a lambda or Supplier<X> to back those expressions:

public <X> void set(Path<X>, Supplier<? extends X> expression) {
    // ...
    X value = expression.get();
    // ...
}

Then:

final Path1<Integer> daysInAWeek = ...;
final Path2<Date> today = ...; 
foo.set(daysInAWeek, () -> 7); // the constant value returning expression.
foo.set(today, () -> Date.todaysDate()); // calculated when invoked.

Each of those foo.set code lines are implicitly declaring a inner class that extends Supplier . You can also create named top-level classes that implement Supplier and pass a instance as the second parameter in set .

Also if you insist in having your own Expression interface/class that is find to as long as it qualifies as a functional interface such as Supplier .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM