Method reference is ambiguous for Thread.sleep

前端 未结 3 1746
臣服心动
臣服心动 2021-02-07 08:29

I\'ve come across a weird problem where a method reference to Thread::sleep is ambiguous but a method with the same signature is not.

package test;          


        
3条回答
  •  故里飘歌
    2021-02-07 08:56

    The problem is that both, Thread.sleep and foo, are overloaded. So there is a circular dependency.

    • In order to find out which sleep method to use, we need to know the target type, i.e. which foo method to invoke
    • In order to find out which foo method to invoke, we need to know the functional signature of the argument, i.e. which sleep method we have selected

    While it’s clear to a human reader that for this scenario only one of the 2×2 combinations is valid, the compiler must follow formal rules that work for arbitrary combinations, therefore, the language designers had to make a cut.

    For the sake of usefulness of method references, there is a special treatment for unambiguous references, like your Test::sleep:

    JLS §15.13.1

    For some method reference expressions, there is only one possible compile-time declaration with only one possible invocation type (§15.12.2.6), regardless of the targeted function type. Such method reference expressions are said to be exact. A method reference expression that is not exact is said to be inexact.

    Note that this distinction is similar to the distinction between implicitly typed lambda expressions (arg -> expression) and explicitly typed lambda expressions ((Type arg) -> expression).

    When you look at JLS, §15.12.2.5., Choosing the Most Specific Method, you’ll see that the signature of a method reference is only used for exact method references, as when choosing the right foo, the decision for the right sleep method has not made yet.

    If e is an exact method reference expression (§15.13.1), then i) for all i (1 ≤ i ≤ k), Ui is the same as Vi, and ii) one of the following is true:

    • R₂ is void.
    • R₁ <: R₂.
    • R₁ is a primitive type, R₂ is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type.
    • R₁ is a reference type, R₂ is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type.

    The above rule has been stated in §15.12.2.5. for non-generic methods, redirecting to §18.5.4 for generic methods (which applies here as your foo methods are generic), containing exactly the same rule with a slightly different wording.

    Since the method reference’s signature is not considered when choosing the most specific method, there is no most specific method and the invocation of foo is ambiguous. The second compiler error is the result of the strategy to continue processing the source code and potentially reporting more errors, instead of stopping the compilation right at the first error. One of the two invocations of foo caused an “incompatible types” error, if that invocation was happening, but actually that has been ruled out due to the “ambiguous invocation” error.

提交回复
热议问题