泛型类型推断不适用于方法链接? [英] Generic type inference not working with method chaining?

查看:160
本文介绍了泛型类型推断不适用于方法链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

无法在Java 7中编译:

  class Map< K,V> {
static< K,V>地图< K,V> empty(){return null;}
Map< K,V> put(K k,V v){return null;}
V get(K k){return null;}
}

class A {
static void f(Map< Integer,String> m){}
public static void main(String [] args){
f(Map.empty());




$ b

它不能推断出<从 Map.empty()返回的code> Map

<$ p $ a> $ javac7 A.java
A.java:10:错误:类A中的方法f不能应用于给定的类型;
f(Map.empty());
^
要求:Map< Integer,String>找到
:Map< Object,Object>
reason:实际参数Map< Object,Object>无法转换为Map< Integer,String>通过方法调用转换
1错误

如果您更改 调用 f(Map。< Integer,String> empty()); 。在Java 8中,它不需要求助于此。



但是,如果将 f 调用更改为 f(Map.empty()。put(1,A)。put(2,B)); ,它无法再次编译, 7和8.为什么?

  $ $ javac7 A.java 
A.java:10:error:method f在A类中不能用于给定的类型;
f(Map.empty()。put(1,A)。put(2,B));
^
要求:Map< Integer,String>找到
:Map< Object,Object>
reason:实际参数Map< Object,Object>无法转换为Map< Integer,String>通过方法调用转换
1错误

$ $ javac8 A.java
A.java:10:错误:不兼容类型:Map< Object,Object>无法转换为Map< Integer,String>
f(Map.empty()。put(1,A)。put(2,B));
^
注意:有些信息已被简化;使用-Xdiags:verbose重新编译以获得完整输出
1错误

$ $ javac8 -Xdiags:verbose A.java
A.java:10:错误:方法f在类中A不能用于给定的类型;
f(Map.empty()。put(1,A)。put(2,B));
^
要求:Map< Integer,String>找到
:Map< Object,Object>
原因:参数不匹配;地图<对象,对象>无法转换为Map< Integer,String>
1错误


解决方案

为什么?



因为泛型类型的类型推断尚未扩展为链式调用。 关于泛型类型推断的java教程:


什么是目标类型的概念已被扩展为包含方法参数。


为什么这个代码:

  f(Map.empty()); 

编译。



但是这段代码doesn 't因为这是一个链式调用:

  f(Map.empty()。put(1,A)。放(2, B)); 






您也可以在< JSR-000335用于JavaTM编程语言的Lambda表达式评估最终版本(具体而言,请参见http://go.microsoft.com/fwlink/?LinkId=15216)。部分D):b
$ b


允许推断chain:在a()。b()中,传递类型从调用b到调用a的信息。这给推理算法的复杂性增加了另一个维度,因为部分信息必须在两个方向上传递;它只适用于删除a()的返回类型对所有实例(例如List)都是固定的。由于目标类型不易导出,因此此功能不适合多表达式模型。但可能会有额外的增强功能,它可能会在未来添加。


所以也许在Java 9中。


This fails to compile in Java 7:

class Map<K,V> {
    static <K,V> Map<K,V> empty() {return null;}
    Map<K,V> put(K k, V v) {return null;}
    V get(K k) {return null;}
}

class A {
    static void f(Map<Integer,String> m){}
    public static void main(String[] args) {
        f(Map.empty());
    }
}

It doesn't infer the concrete type of the Map being returned from Map.empty():

$ javac7 A.java
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty());
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: actual argument Map<Object,Object> cannot be converted to Map<Integer,String> by method invocation conversion
1 error

It compiles if you change the f call to f(Map.<Integer,String>empty());. In Java 8, it works without having to resort to this.

But if you change the f call to f(Map.empty().put(1,"A").put(2,"B"));, it fails to compile once again, on both Java 7 and 8. Why?

$ $javac7 A.java 
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty().put(1,"A").put(2,"B"));
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: actual argument Map<Object,Object> cannot be converted to Map<Integer,String> by method invocation conversion
1 error

$ $javac8 A.java
A.java:10: error: incompatible types: Map<Object,Object> cannot be converted to Map<Integer,String>
        f(Map.empty().put(1,"A").put(2,"B"));
                                    ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

$ $javac8 -Xdiags:verbose A.java
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty().put(1,"A").put(2,"B"));
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: argument mismatch; Map<Object,Object> cannot be converted to Map<Integer,String>
1 error

解决方案

Why ?

Because the type inference of generics types has not been expanded to chained invocation.

From the java tutorial on generics type inference:

The notion of what is a target type has been expanded to include method arguments.

That is why this code:

f(Map.empty());

compiles.

But this code doesn't because this is a chained invocation:

f(Map.empty().put(1,"A").put(2,"B"));


You can also find a small paragraph in the JSR-000335 Lambda Expressions for the JavaTM Programming Language Final Release for Evaluation (specifically part D):

There has been some interest in allowing inference to "chain": in a().b(), passing type information from the invocation of b to the invocation of a. This adds another dimension to the complexity of the inference algorithm, as partial information has to pass in both directions; it only works when the erasure of the return type of a() is fixed for all instantiations (e.g. List). This feature would not fit very well into the poly expression model, since the target type cannot be easily derived; but perhaps with additional enhancements it could be added in the future.

So maybe in Java 9.

这篇关于泛型类型推断不适用于方法链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆