【问题标题】:Type inference in javajava中的类型推断
【发布时间】:2015-09-01 08:14:24
【问题描述】:

您能否解释一下为什么下面的工作在某种程度上是可行的。 在我看来,java类型系统推断R的类型很弱

public class Test {

interface Parser<A,R>{
    R parse(A a);
}

static class ResponseParser implements Parser<String,Integer>{

    public Integer parse(String s) {
        return Integer.parseInt(s) + 1;
    }
}

interface Function<A,R>{
    R with(A a);
}

public static <A,R,P extends Parser<A,R>> Function<P,R> getResult(final A res){
        return new Function<P, R>() {
            public R with(P parser) {
                return parser.parse(res);
            }
        };
}

public static void main(String [] args){
    Function<Parser<String,Integer>, Integer> func = getResult("1");
    //this works
    func.with(new ResponseParser());
    // why this does not work
    getResult("1").with(new ResponseParser());
}


}

【问题讨论】:

  • 我只是想了解为什么没有推断出“R”
  • 那么下面是怎么遵守的呢? Function, Integer> func = getResult("1"); //这工作 func.with(new ResponseParser());
  • 和 getResult("1").with(new ResponseParser());甚至不编译
  • AFAIK,编译器将检查传递给 with() 的 ResponseParser 是否与 getResult() 的返回类型兼容。所以要做到这一点,它需要知道 getResult() 的返回类型。但它不能,因为您没有为 getResult() 方法调用指定任何泛型类型,并且它无法推断它们,因为返回的值没有像第一个示例中那样分配给任何变量。 Java 不会从传递给方法的参数中推断方法 getResult() 的类型,该方法调用 getResult() 的结果。
  • @RealSkeptic,他不使用原始类型。

标签: java generics types


【解决方案1】:

getResult("1").with(new ResponseParser()); 表达式中,getResult("1") 子表达式的类型无法从上下文中正确推断。你认为它应该是Function&lt;? extends Parser&lt;String, Integer&gt;, Integer&gt;,但是这个子表达式对Integer一无所知。在第一种情况下,您将结果分配给Function&lt;Parser&lt;String,Integer&gt;, Integer&gt;,因此可以解析R = Integer类型,但是当您只是调用其他方法时,它不起作用。

您可以通过推迟推断返回类型的必要性来解决此问题。像这样的:

interface ParserFunction<A> {
    <R> R with(Parser<A, R> a);
}

public static <A> ParserFunction<A> getResult(final A res){
        return new ParserFunction<A>() {
            public <R> R with(Parser<A, R> parser) {
                return parser.parse(res);
            }
        };
}

现在getResult("1").with(new ResponseParser()); 有效。

【讨论】:

  • 只是想了解为什么在这种情况下它能够推断类型...实际上,希望了解它是如何推断 R 的类型
  • @Abhishekkapoor,在固定代码中,R 类型不应被推断为getResult("1")。它推断为with,在这里它可能知道new ResponseParser() 是返回Integer 的解析器。
  • 这是否意味着您推迟了 R 的推断,以便它可以由子表达式推断
  • @Abhishekkapoor,是的,完全正确。
【解决方案2】:

泛型仅由编译器使用,以确保您不违反指定类型的规则。在运行时,所有泛型都转换为Object,但类型安全得到了保证,因为编译器会通知您任何违规或类型安全。要实现这一点,您需要告诉编译器您正在使用什么尝试,这就是不推断泛型的原因。

使用 java 泛型检查擦除 https://docs.oracle.com/javase/tutorial/java/generics/genMethods.html

【讨论】:

    猜你喜欢
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    相关资源
    最近更新 更多