简体   繁体   English

为什么Java编译器不能解决这个问题呢?

[英]Why can't the Java compiler figure this out?

Why is the compiler unable to infer the correct type for the result from Collections.emptySet() in the following example? 为什么编译器无法在以下示例中从Collections.emptySet()推断出结果的正确类型?

import java.util.*;
import java.io.*;

public class Test {
    public interface Option<A> {
        public <B> B option(B b, F<A,B> f);
    }

    public interface F<A,B> {
        public B f(A a);
    }

    public Collection<String> getColl() {
        Option<Integer> iopt = null;

        return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
            public Collection<String> f(Integer i) {
                return Collections.singleton(i.toString());
            }
        });
    }
}

Here's the compiler error message: 这是编译器错误消息:

knuttycombe@knuttycombe-ubuntu:~/tmp/java$ javac Test.java 
Test.java:16: <B>option(B,Test.F<java.lang.Integer,B>) in 
Test.Option<java.lang.Integer> cannot be applied to (java.util.Set<java.lang.Object>,
<anonymous Test.F<java.lang.Integer,java.util.Collection<java.lang.String>>>)
            return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
                   ^
1 error

Now, the following implementation of getColl() works, of course: 现在,getColl()的以下实现当然有效:

    public Collection<String> getColl() {
        Option<Integer> iopt = null;

        Collection<String> empty = Collections.emptySet();
        return iopt.option(empty, new F<Integer, Collection<String>>() {
            public Collection<String> f(Integer i) {
                return Collections.singleton(i.toString());
            }
        });
    }

and the whole intent of the typesafe methods on Collections is to avoid this sort of issue with the singleton collections (as opposed to using the static variables.) So is the compiler simply unable to perform inference across multiple levels of generics? 并且关于集合的类型安全方法的整个意图是避免单例集合的这种问题(而不是使用静态变量。)那么编译器是否无法跨多个泛型级别执行推理? What's going on? 这是怎么回事?

Java needs a lot of hand holding with its inference. Java需要通过推理进行大量的手工操作。 The type system could infer better in a lot of cases but in your case the following will work: 类型系统可以在很多情况下更好地推断,但在您的情况下,以下将起作用:

print("Collections.<String>emptySet();");

First you can narrow down your problem to this code: 首先,您可以将问题范围缩小到以下代码:

public class Test { 
    public void option(Collection<String> b) {
    }

    public void getColl() {
        option(Collections.emptySet());
    }
}

This does not work, you need a temporary variable or else the compiler cannot infer the type. 这不起作用,需要一个临时变量,否则编译器无法推断出类型。 Here is a good explanation of this problem: Why do temporary variables matter in case of invocation of generic methods? 以下是对此问题的一个很好的解释: 为什么临时变量在调用泛型方法时很重要?

Collections.emptySet() is not a Collection<String> unless Java knows that it needs a Collection<String> there. Collections.emptySet()不是Collection<String>除非Java知道它需要Collection<String> In this case, it appears that the compiler is being somewhat silly about the order that it tries to determine types, and tries to determine the return type of Collections.emptySet() before trying to determine the intended template parameter type for B is actually String . 在这种情况下,似乎编译器对它尝试确定类型的顺序有些愚蠢,并且在尝试确定B的预期模板参数类型之前尝试确定Collections.emptySet()的返回类型实际上是String

The solution is to explictly state that you need Collections.<String>emptySet() , as mentioned by GaryF. 解决方案是明确声明您需要Collections.<String>emptySet() ,如GaryF所述。

It looks like a typecasting issue - ie, that it's being required to cast Object (in Set<Object> , which would be the type of the empty set) to String . 它看起来像一个类型转换问题 - 也就是说,它需要将Object (在Set<Object> ,这将是空集的类型)转换为String Downcasts are not, in the general case, safe. 在一般情况下,堕落者不是安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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