繁体   English   中英

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

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

为什么编译器无法在以下示例中从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());
            }
        });
    }
}

这是编译器错误消息:

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

现在,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());
            }
        });
    }

并且关于集合的类型安全方法的整个意图是避免单例集合的这种问题(而不是使用静态变量。)那么编译器是否无法跨多个泛型级别执行推理? 这是怎么回事?

Java需要通过推理进行大量的手工操作。 类型系统可以在很多情况下更好地推断,但在您的情况下,以下将起作用:

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

首先,您可以将问题范围缩小到以下代码:

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

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

这不起作用,需要一个临时变量,否则编译器无法推断出类型。 以下是对此问题的一个很好的解释: 为什么临时变量在调用泛型方法时很重要?

Collections.emptySet()不是Collection<String>除非Java知道它需要Collection<String> 在这种情况下,似乎编译器对它尝试确定类型的顺序有些愚蠢,并且在尝试确定B的预期模板参数类型之前尝试确定Collections.emptySet()的返回类型实际上是String

解决方案是明确声明您需要Collections.<String>emptySet() ,如GaryF所述。

它看起来像一个类型转换问题 - 也就是说,它需要将Object (在Set<Object> ,这将是空集的类型)转换为String 在一般情况下,堕落者不是安全的。

暂无
暂无

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

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