Java泛型Predicate使用<? extends Person>后调用test方法编译失败问题
问题原因分析
你遇到的编译错误核心在于**Predicate<? extends Person>的类型通配符使用错误**,这涉及Java泛型中消费者类型的逆变特性:
Predicate<T>是消费者类型(它的test方法接收T类型参数并消费它),消费者类型遵循逆变原则——即如果A是B的父类,Predicate<B>可赋值给Predicate<? super A>,而非Predicate<? extends A>。- 声明返回
Predicate<? extends Person>时,编译器会认为这个Predicate的目标类型是某个未知的Person子类(可能是Person本身、Employee或其他未定义的子类)。此时调用test方法,编译器无法确定传入的实例是否匹配这个未知类型:比如若Predicate实际是Predicate<Employee>,传入Person实例会类型不匹配;若它是Predicate<Person>,传入Employee是合法的,但编译器不会做这种假设。为保证类型安全,编译器直接禁止传入任何非null的具体实例。
解决方案
如果你希望这个Predicate能适配Person及其所有子类,直接将返回类型改为Predicate<Person>即可:
// 修正后的startsA方法 public Predicate<Person> startsA() { return person -> person.getName().startsWith("A"); }
修改后,startsA().test(new Employee())和startsA().test(new Person())都能正常编译:
Predicate<Person>的test方法接受Person类型参数,Employee作为Person子类,完全符合参数要求;- 这个Predicate可以自然处理所有Person子类实例,因为它们都继承了
getName()方法。
额外说明
如果确实需要用通配符增强灵活性(比如允许返回针对特定子类的Predicate),可以使用Predicate<? super Person>——这表示该Predicate可接受Person或其父类型实例(不过这里Person已是顶层类,实际意义不大)。但对你的场景而言,直接使用Predicate<Person>是最简洁且贴合需求的方案。
内容的提问来源于stack exchange,提问作者AntonBoarf
相关产品推荐
相关产品推荐

