奇怪的汇编问题

发布于 2025-02-10 14:18:29 字数 1563 浏览 1 评论 0原文

以下类将不会编译:

public class Thing {

    public static <T> T foo(java.util.function.Supplier<T> supplier) {
        return supplier.get();
    }

    public static <T> T bar(java.util.function.Function<Integer, T> function) {
        return function.apply(42);
    }

    public static void main(String... args) {
        System.out.println(foo(() -> "hello")); // 1
        System.out.println(bar(any -> "hello")); // 2 !!!
        System.out.println(bar((Integer any) -> "hello")); // 3
        System.out.println(Thing.<String>bar(any -> "hello")); // 4
        println(bar(any -> "hello")); // 5
    }

    private static void println(String string) {
        System.out.println(string);
    }
}

该问题在main()方法(所有其他行都很好)中在线[2]:

[ERROR] .../Thing.java:[13,19] reference to println is ambiguous
    both method println(char[]) in java.io.PrintStream and method println(java.lang.String) in java.io.PrintStream match
[ERROR] .../Thing.java:[13,31] incompatible types: inference variable T has incompatible bounds
    lower bounds: char[],java.lang.Object
    lower bounds: java.lang.String

我不明白为什么编译器认为在bar()的返回类型char []字符串),无法决定println()println()< /代码>应使用方法。在行[1]上,可以推断出foo()的返回类型是string和在线[3],我不明白如何指定如何指定类型任何Integer)会有所帮助,因为它不能让其他任何东西给定bar()方法的签名。

The following class will not compile:

public class Thing {

    public static <T> T foo(java.util.function.Supplier<T> supplier) {
        return supplier.get();
    }

    public static <T> T bar(java.util.function.Function<Integer, T> function) {
        return function.apply(42);
    }

    public static void main(String... args) {
        System.out.println(foo(() -> "hello")); // 1
        System.out.println(bar(any -> "hello")); // 2 !!!
        System.out.println(bar((Integer any) -> "hello")); // 3
        System.out.println(Thing.<String>bar(any -> "hello")); // 4
        println(bar(any -> "hello")); // 5
    }

    private static void println(String string) {
        System.out.println(string);
    }
}

The issue is on line [2] in the main() method (all other lines are fine):

[ERROR] .../Thing.java:[13,19] reference to println is ambiguous
    both method println(char[]) in java.io.PrintStream and method println(java.lang.String) in java.io.PrintStream match
[ERROR] .../Thing.java:[13,31] incompatible types: inference variable T has incompatible bounds
    lower bounds: char[],java.lang.Object
    lower bounds: java.lang.String

I don't understand why the compiler thinks there is an ambiguity on the return type of bar() (char[] or String) and can't decide which flavor of println() method should be used. On line [1], it can infer that the return type of foo() is String and on line [3], I don't understand how specifying the type of any (Integer) helps because it could not be anything else given the signature of the bar() method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薄暮涼年 2025-02-17 14:18:29

这是因为隐式键入的lambda 任何 - &gt; “你好”不是与适用性相关,因此在确定哪种类型的call bar(任何 - &gt;“ hello”)时,实际上被忽略://docs.oracle.com/javase/specs/jls/se17/html/jls-18.html#jls-18.5.2.1“ rel =“ nofollow noreferrer”> nofollow noreferrer“> invocation类型type type type penperion ,为了选择正确的println调用。

可以从第一个链接中找到理由:

隐式键入的lambda表达式或不精确方法表达式表达式在解决目标类型之前足够模糊,该目标类型与适用性无关。他们只是被忽略(除了预期的Arity除外),直到分辨率分辨率为止。

因此,除了我们将其传递到system.out.println的事实外,bar的返回类型几乎没有界限类型。编译器试图推断我们正在尝试使用上面第二个链接中的规则来调用哪个过载,但是println(string)println(char [])都看起来像有效的超载!

其他行工作的原因是:

  • system.out.println(foo(() - &gt;“ hello”));

  • system.out.println(bar(((integer noy any) - &gt;“ hello” hello'' );

    这些lambdas都与适用性有关,因为它们是明确键入lambdas (尽管该规则有一些例外)。请注意,没有参数的lambda被视为明确键入的lambda。

  • system.out.println(物质

    由于您提供了bar的类型参数,因此编译器无需使用类型推荐来确定它。现在可以琐碎地确定bar返回字符串,因此您必须调用println(string)


  • println(bar(Any -&gt;“ Hello”));

    只有一个println的过载,即使我们不知道bar返回string我们仍然可以看到bar调用将传递给println(string)

我建议您查看与适用性无关的表达式列表,并与之相处:)

This is because the implicitly typed lambda any -> "hello" is not pertinent to applicability, and so it is practically ignored when determining what type the call bar(any -> "hello") should be (See Invocation Type Inference sections of the JLS), in order to select the correct println call.

The justification can be found from the first link:

The meaning of an implicitly typed lambda expression or an inexact method reference expression is sufficiently vague prior to resolving a target type that arguments containing these expressions are not considered pertinent to applicability; they are simply ignored (except for their expected arity) until overload resolution is finished.

So other than the fact that we are passing it to System.out.println, there are practically no bounds on the return type of bar at all - it could be any reference type. The compiler tries to infer which overload we are trying to call using the rules in that second link above, but println(String) and println(char[]) both seem like valid overloads!

The reasons why the other lines work are:

  • System.out.println(foo(() -> "hello"));

  • System.out.println(bar((Integer any) -> "hello"));

    these lambdas are all pertinent to applicability, because they are explicitly typed lambdas (though this rule has some exceptions). Note that a lambda with no parameters counts as an explicitly typed lambda.

  • System.out.println(Thing.<String>bar(any -> "hello"));

    Since you have provided the type parameter of bar, the compiler does not need to determine it using type inference. It can now be trivially determined that bar returns String, so you must be calling println(String).

  • println(bar(any -> "hello"));

    There is only one overload of println to pick, so even though we can't know that bar returns String from the lambda, we can still do it by seeing that the bar call is being passed to println(String).

I recommend that you have a look at the list of expressions that are not pertinent to applicability and play around with them :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文