Java Lambda参数类型不兼容:期望Object却传入SomeOtherClass
问题解析:为什么
Predicate<Object>无法接受子类参数的Lambda? 这是个典型的泛型协变/逆变问题,咱们一步步拆解清楚:
为什么第一个例子能正常运行?
你第一个构造器的参数是Object,Java里所有类都默认继承自Object,所以SomeOtherClass的实例可以自动向上转型为Object——这是Java基础的多态特性,完全符合类型规则。
为什么第二个例子会报错?
核心原因在于泛型的不变性,以及Predicate接口的泛型参数是输入型参数(遵循逆变逻辑):
Predicate<Object>代表的是「一个能接受任意Object类型参数的谓词」——也就是说,这个Predicate的test方法必须能处理所有Object子类(比如String、Integer、SomeOtherClass等等)。- 而你写的
(SomeOtherClass s) -> { return true; }本质上是Predicate<SomeOtherClass>,它的test方法只能接受SomeOtherClass类型的参数,处理范围比Object小得多。
Java的泛型默认是不变的:哪怕SomeOtherClass是Object的子类,Predicate<SomeOtherClass>也不是Predicate<Object>的子类型。编译器会阻止这种赋值,因为这会破坏类型安全——如果允许这么做,后续代码调用这个Predicate时可能传入一个Integer,但你的Lambda只能处理SomeOtherClass,运行时必然出错。
怎么解决你的需求?
你想要构造器能接受处理多种子类(比如SomeOtherClass、SomeOtherClassXPTO)的Predicate,有两种常见方案:
方案1:使用泛型类+通配符下限
把MyClass改成泛型类,构造器参数用Predicate<? super T>(逆变通配符),这样就能接受处理T或T子类的Predicate:
import java.util.function.Predicate; public class MyClass<T> { MyClass(Predicate<? super T> b) { // 你的业务代码 } }
使用时:
// 接受处理SomeOtherClass的Lambda MyClass<SomeOtherClass> x = new MyClass<>((SomeOtherClass s) -> { return true; }); // 接受处理SomeOtherClassXPTO的Lambda MyClass<SomeOtherClassXPTO> y = new MyClass<>((SomeOtherClassXPTO s) -> { return true; });
方案2:直接使用Predicate<?>
如果你不想用泛型类,可以把构造器参数改成Predicate<?>,它可以接受任何类型的Predicate:
import java.util.function.Predicate; public class MyClass { MyClass(Predicate<?> b) { // 注意:这里调用b.test()时只能传入Object类型参数 } }
这种方式的局限性是,在构造器内部调用Predicate的test方法时,只能传入Object类型的参数,因为Predicate<?>的test方法参数是Object。
内容的提问来源于stack exchange,提问作者Joao
相关产品推荐
相关产品推荐

