为什么将此Java方法调用视为模棱两可? [英] Why is this Java method call considered ambiguous?

查看:92
本文介绍了为什么将此Java方法调用视为模棱两可?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了奇怪的错误消息,我认为这可能是不正确的.考虑以下代码:

 public class Overloaded {
    public interface Supplier {
        int get();
    }

    public interface Processor {
        String process(String s);
    }

    public static void load(Supplier s) {}
    public static void load(Processor p) {}

    public static int genuinelyAmbiguous() { return 4; }
    public static String genuinelyAmbiguous(String s) { return "string"; }

    public static int notAmbiguous() { return 4; }
    public static String notAmbiguous(int x, int y) { return "string"; }

    public static int strangelyAmbiguous() { return 4; }
    public static String strangelyAmbiguous(int x) { return "string"; }
}
 

如果我有一个看起来像这样的方法:

 // Exhibit A
public static void exhibitA() {
    // Genuinely ambiguous: either choice is correct
    load(Overloaded::genuinelyAmbiguous); // <-- ERROR
    Supplier s1 = Overloaded::genuinelyAmbiguous;
    Processor p1 = Overloaded::genuinelyAmbiguous; 
}
 

我们得到的错误是很合理的;可以将load()的参数分配给其中一个,因此我们收到一条错误消息,指出方法调用不明确.

相反,如果我有一个看起来像这样的方法:

 // Exhibit B
public static void exhibitB() {
    // Correctly infers the right overloaded method
    load(Overloaded::notAmbiguous);
    Supplier s2 = Overloaded::notAmbiguous;
    Processor p2 = Overloaded::notAmbiguous; // <-- ERROR
}
 

load()的调用很好,并且不出所料,我不能将方法引用同时分配给SupplierProcessor,因为它不是模棱两可的:Overloaded::notAmbiguous无法分配给p2.

现在这很奇怪.如果我有这样的方法:

 // Exhibit C
public static void exhibitC() {
    // Complains that the reference is ambiguous
    load(Overloaded::strangelyAmbiguous); // <-- ERROR
    Supplier s3 = Overloaded::strangelyAmbiguous;
    Processor p3 = Overloaded::strangelyAmbiguous; // <-- ERROR
}
 

编译器抱怨对load()的调用不明确(error: reference to load is ambiguous),但是与图表A不同,我无法将方法引用同时分配给SupplierProcessor.如果确实是模棱两可,我认为我应该能够像表A中一样将s3p3分配给两个重载的参数类型,但是在p3上却出现错误,指出该error: incompatible types: invalid method reference.附件C中的第二个错误是有道理的,Overloaded::strangelyAmbiguous 不是可以分配给Processor,但是如果不能分配,为什么它仍然被认为是模棱两可的?

在确定选择哪个重载版本时,方法引用推断似乎仅查看FunctionalInterface的优点.在变量分配中,检查了参数的类型,这导致重载方法与变量分配之间存在差异.

在我看来,这就像一个错误.如果不是这样,则至少错误消息是不正确的,因为当两个选择之间只有一个是正确的时,可以说没有歧义.

解决方案

您的问题与 JLS §15.12.2.2.,在解决重载过程中将它们从适用性检查中跳过,从而导致模棱两可.

在这种情况下,您需要明确指定类型,例如:

load((Processor) Overloaded::genuinelyAmbiguous);
load(( Supplier) Overloaded::strangelyAmbiguous);

I've come across a strange error message that I believe may be incorrect. Consider the following code:

public class Overloaded {
    public interface Supplier {
        int get();
    }

    public interface Processor {
        String process(String s);
    }

    public static void load(Supplier s) {}
    public static void load(Processor p) {}

    public static int genuinelyAmbiguous() { return 4; }
    public static String genuinelyAmbiguous(String s) { return "string"; }

    public static int notAmbiguous() { return 4; }
    public static String notAmbiguous(int x, int y) { return "string"; }

    public static int strangelyAmbiguous() { return 4; }
    public static String strangelyAmbiguous(int x) { return "string"; }
}

If I have a method that looks like this:

// Exhibit A
public static void exhibitA() {
    // Genuinely ambiguous: either choice is correct
    load(Overloaded::genuinelyAmbiguous); // <-- ERROR
    Supplier s1 = Overloaded::genuinelyAmbiguous;
    Processor p1 = Overloaded::genuinelyAmbiguous; 
}

The error we get makes perfect sense; the parameter to load() can be assigned to either, so we get an error that states the method call is ambiguous.

Conversely, if I have a method that looks like this:

// Exhibit B
public static void exhibitB() {
    // Correctly infers the right overloaded method
    load(Overloaded::notAmbiguous);
    Supplier s2 = Overloaded::notAmbiguous;
    Processor p2 = Overloaded::notAmbiguous; // <-- ERROR
}

The call to load() is fine, and as expected, I cannot assign the method reference to both Supplier and Processor because it is not ambiguous: Overloaded::notAmbiguous cannot be assigned to p2.

And now the weird one. If I have a method like this:

// Exhibit C
public static void exhibitC() {
    // Complains that the reference is ambiguous
    load(Overloaded::strangelyAmbiguous); // <-- ERROR
    Supplier s3 = Overloaded::strangelyAmbiguous;
    Processor p3 = Overloaded::strangelyAmbiguous; // <-- ERROR
}

The compiler complains that the call to load() is ambiguous (error: reference to load is ambiguous), but unlike Exhibit A, I cannot assign the method reference to both Supplier and Processor. If it were truly ambiguous, I feel I should be able to assign s3 and p3 to both overloaded parameter types just as in Exhibit A, but I get an error on p3 stating that error: incompatible types: invalid method reference. This second error in Exhibit C makes sense, Overloaded::strangelyAmbiguous isn't assignable to Processor, but if it isn't assignable, why is it still considered ambiguous?

It would seem that the method reference inference only looks at the arity of the FunctionalInterface when determining which overloaded version to select. In the variable assignment, arity and type of parameters are checked, which causes this discrepancy between the overloaded method and the variable assignment.

This seems to me like a bug. If it isn't, at least the error message is incorrect, since there is arguably no ambiguity when between two choices only one is correct.

解决方案

Your question is very similar to this one.

The short answer is:

Overloaded::genuinelyAmbiguous;
Overloaded::notAmbiguous;
Overloaded::strangelyAmbiguous;

all these method references are inexact (they have multiple overloads). Consequently, according to the JLS §15.12.2.2., they are skipped from the applicability check during overload resolution, which results in ambiguity.

In this case, you need to specify the type explicitly, for example:

load((Processor) Overloaded::genuinelyAmbiguous);
load(( Supplier) Overloaded::strangelyAmbiguous);

这篇关于为什么将此Java方法调用视为模棱两可?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆