带受限泛型的Lambda表达式编译错误原因咨询
先把你的代码和编译错误清晰展示出来:
public class MyTest { public static void main(String[] args) { SubObject[] array = new SubObject[5]; Iterator<? extends SuperObject> iterator = Arrays.asList((SuperObject[]) array).iterator(); Iterable<? extends SuperObject> iterable = () -> iterator; } } class SuperObject {}; class SubObject extends SuperObject{};
编译报错信息:
MyTest.java:9: error: incompatible types: bad return type in lambda expression
Iterable<? extends SuperObject> iterable = () -> iterator;
^
Iterator<CAP#1> cannot be converted to Iterator
where CAP#1 is a fresh type-variable:
CAP#1 extends SuperObject from capture of ? extends SuperObject
咱们来拆解这个错误的核心原因:
首先得明确Iterable<? extends SuperObject>的真实含义:它代表这个Iterable的元素类型是某个特定的、未知的SuperObject子类(包括SuperObject本身)。对应到Iterable的方法签名上,它的iterator()方法必须返回一个Iterator<CAP#1>——这里的CAP#1就是编译器自动生成的“特定未知类型”(通配符捕获类型)。
而你定义的iterator变量类型是Iterator<? extends SuperObject>,它表示这个迭代器可以迭代任意SuperObject的子类,并非固定的某个特定类型。
问题出在lambda的类型推断逻辑上:编译器会把lambda的目标函数式接口解析为Iterable<CAP#1>,要求lambda返回的迭代器必须严格匹配Iterator<CAP#1>;但你的iterator是Iterator<? extends SuperObject>,这两个类型并不兼容——因为CAP#1是一个确定的未知类型,而? extends SuperObject是任意未知类型,编译器无法保证它们指向同一个具体类型,因此抛出了类型不兼容的错误。
如果换成匿名内部类的写法,你会发现代码能正常编译:
Iterable<? extends SuperObject> iterable = new Iterable<>() { @Override public Iterator<? extends SuperObject> iterator() { return iterator; } };
这是因为匿名内部类的方法返回类型明确声明为Iterator<? extends SuperObject>,编译器可以直接匹配Iterable<? extends SuperObject>的通配符要求;而lambda的类型推断会更严格,它会试图将目标类型的通配符捕获为一个具体类型,再要求返回值严格匹配该类型。
内容的提问来源于stack exchange,提问作者Steve Brandli

