【问题标题】:Inferring generic types of nested static generic functions推断嵌套静态泛型函数的泛型类型
【发布时间】:2011-06-07 11:11:07
【问题描述】:

Java 编译器是否能够从其上下文中推断出通用静态函数的类型作为另一个通用静态函数的参数?

例如,我有一个简单的 Pair 类:

public class Pair<F, S> {

    private final F mFirst;

    private final S mSecond;

    public Pair(F first, S second) {
        mFirst  = checkNotNull(first);
        mSecond = checkNotNull(second);
    }

    public static <F, S, F1 extends F, S1 extends S> Pair<F, S> of(F1 first, S1 second) {
        return new Pair<F, S>(first, second);
    }

    public F first() {
        return mFirst;
    }

    public S second() {
        return mSecond;
    }

    // ...
}

我有以下通用静态函数:

public static <F, P extends Pair<F, ?>> Function<P, F> deferredFirst() {
    return (Function<P, F>)DEFERRED_FIRST;
}

private static final Function<Pair<Object, ?>, Object> DEFERRED_FIRST = 
        new Function<Pair<Object,?>, Object>() {

    @Override
    public Object apply(Pair<Object, ?> input) {
        return input.first();
    }
};

我希望使用如下(Collections2.transform is from Google Guava):

List<Pair<Integer, Double>> values = ...
Collection<Integer> firsts = Collections2.transform(values, 
        Pair.deferredFirst());

编译器抱怨的对象:

The method transform(Collection<F>, Function<? super F,T>) in the type 
Collections2 is not applicable for the arguments 
(List<Pair<Integer,Double>>, Function<Pair<Object,?>,Object>)

因此,编译器似乎无法将为 transform() 推断的类型传播到 deferredFirst(),因为它认为它们是对象。

强制编译器以以下任何一种方式理解类型都有效:

Function<Pair<Integer, ?>, Integer> func = Pair.deferredFirst();
Collection<Integer> firsts = Collections2.transform(values, func);


Collection<Integer> firsts = Collections2.transform(values, 
        Pair.<Integer, Pair<Integer, ?>>deferredFirst());

是否可以更改任一函数的签名以允许编译器推断/传播类型?

编辑:对于波西米亚人来说,上面的示例可以用于以下一种可能的方法:

public static int sumSomeInts(List<Pair<Integer, Double>> values) {
    Collection<Integer> ints = Collections2.transform(values, 
            Pair.deferredFirst());
    int sum = 0;
    for(int i : ints)
        sum += i;
    return sum;
}

【问题讨论】:

  • 当你有class A&lt;F,S&gt; { public &lt;F,S&gt; void method(){}}时要小心。我的猜测是方法中的 F,S 覆盖了你的类中的那些(即相当于 class A&lt;F,S&gt; { public &lt;P,Q&gt; void method(){}}

标签: java generics guava type-inference


【解决方案1】:

类型推断是令人讨厌和复杂的。他们必须在某个地方停下来。考虑

static <T> T foo();

String s = foo();

print( foo() )

在赋值上下文中,程序员的意图很明确,T应该是String

在下一行,没有那么多。

print 方法不是一个非常公平的例子,它严重过载。假设print 没有被重载,它的参数类型是固定的,那么T 可以很清楚的推断出来。编译器不应该足够聪明来弄清楚吗?

这听起来很合理,直到有人冒险阅读相关的规范文本,15.12 Method Invocation Expressions 祝你一切顺利!

太复杂了,连编译器的作者都看不懂。 javac 和其他编译器中存在大量源自规范的这一部分的错误。

【讨论】:

    【解决方案2】:

    试试这个泛型功夫:

    public static int sumSomeInts(List<Pair<Integer, Double>> values) {
        Collection<Integer> ints = Collections2.transform(values, 
            Pair.<Integer, Double>deferredFirst());
        int sum = 0;
        for(int i : ints)
            sum += i;
        return sum;
    }
    

    您可以键入方法调用并将泛型传递给下一个调用。

    我不确定此处使用的确切泛型参数,因为您没有包含足够的代码。如果您粘贴问题所在的整个方法,我将编辑此答案以使其编译。 已编辑:包含来自问题的新信息

    如果它编译,请告诉我。如果不是那个解决方案,它将很接近。关键是使用Class.&lt;Type&gt;staticMethod()语法键入静态方法。

    【讨论】:

    • 感谢您的帮助。因为似乎没有在嵌套调用中显式添加类型的情况下没有解决方案,所以我接受了不可靠的回答,因为它有更多关于该问题的一般信息。
    【解决方案3】:

    我刚才想出的是:

    @SuppressWarnings("rawtypes")
    private static final Function ExtractFirst = new Function() {
        @Override
        public Object apply(final Object from) {
            Preconditions.checkNotNull(from);
            return ((Pair)from).first;
        }
    };
    
    @SuppressWarnings("unchecked")
    public static <A> Function<Pair<A,?>,A> extractFirst() {
        return ExtractFirst;
    }
    

    不要让“SuppressWarnings”让您失望,它可以正常工作。

    例子:

    List<Pair<String,String>> pairs = ImmutableList.of(Pair.of("a", "b"),
        Pair.of("c", "d"),Pair.of("e", "f"));
    Iterable<String> firsts = Iterables.transform(pairs,
        Pair.<String>extractFirst());
    

    很遗憾,是的,您必须向 extractFirst() 提供通用参数。我认为这是你能得到的最好的。

    【讨论】:

      猜你喜欢
      • 2013-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      相关资源
      最近更新 更多