这看起来很基本,但我不能理解为什么我的代码不能编译.

我有一个具有String name属性的class Person和一个getName()的Getter.

我创造了一个Employee class extends Person

我有这样一个方法:

public Predicate<? extends Person> startsA() {
        return p -> p.getName().startsWith("A");
}

所以我希望这个方法适用于Person的所有子类

但这段代码无法编译:

startsA().test(new Employee());
startsA().test(new Person());

我不明白为什么

推荐答案

泛型被go 掉了一个元级别.你需要站在编者的立场上走一步才能理解它们.

我经常看到泛型的错误,你似乎也犯了这样的错误,你认为Predicate<? extends Person>意味着‘这是一个可以测试任何人的谓词.一个员工,一个客户-并不重要,因此,’任何扩展人‘都是正确的.

But that is not what that means.

毕竟,想象一下这意味着什么.那么Predicate<Person>是什么呢?一个只能专门测试new Person()而不能测试new Employer()的谓词?Java不是这样工作的--Employer的任何实例都可以用作Person,所以这将是非常奇怪的.

事实上,Predicate<Person>在这里的意思就是您想要的:可以是test any person的谓词对象.

那么Predicate<? extends Person>是什么意思呢?这一点:

可以测试的谓词...我真的不知道它能测试什么.我所知道的是,无论它是什么,它都是某种类型,要么是人,要么是其子类型.

那么,这样的事情有什么意义呢?在这个特定的情况下(对于谓词)并不是很多.让我们转而考虑列表.我们有3种不同的相关类型(记住,Integer和Double都是扩展数字,数字扩展对象)

  • List<? extends Number>
  • List<? super Number>
  • List<Number>

您可以将List<Integer>对象传递给接受List<? extends Number>个的方法.将它传递给一个接受List<Number>个的方法.为什么不-整数扩展了数字,对吗?啊,但是inside generics,这是不变的,比如,不,你不能只是用子类型替换一个类型.毕竟,我可以将Double对象加到List<Number>个上.我可以将数字宾语添加到我的列表中,双重宾语是数字宾语,Qed.

但是,在List<Integer>的基础上加上一个双重对象,这是不好的.因此,List<? extends Number>个是必需的--试试看,您cannot会向这样的列表中添加内容.出于同样的原因:List<? extends Number>个并不意味着:"一个可以容纳数字的列表--任何数字".恰恰相反.它的意思是:"一个可以容纳的列表……我不知道它能容纳什么(因此有问号!)--我只知道,无论它容纳什么,它都是数字.或者数字的任何子类).考虑到这一点,list.get(5)将返回一个Number类型的表达式(考虑到我们所知的少数几件事,这是安全的),但你不能向它添加任何东西(除了字面null的理论用例,它是所有类型).

特别是对于Predicate,Predicate<? extends>是完全没有用的,无论如何都不应该出现.Predicate<? super X>可能会很方便.毕竟,这意味着:"一个可以测试的谓词……我不知道它可以测试什么.我所知道的是,它要么是X,要么是super种类型的X".考虑到这些信息,.test(instanceOfX)是可以接受的.

Java相关问答推荐

我们如何直接使用kerminldap服务票证来通过ldap进行身份验证并形成LDAP上下文

当列顺序更改时,Table View列列表的Change. wasPermanted()总是返回假

我可以在regex中的字符类中放置断言吗?

使用Apache Poi MQLSlideShow,在XSLFTable表中,我们可以在文本段落后面的每个单元格中包含圆角矩形吗?

Listview—在Android Java中正确链接项目时出错

如何使用jooq generator将表名和列名映射为人类可读的?

将数组整体转换为链接表

在运行MVN测试时,为什么构建失败,并显示了java.lang.ClassNotFoundException:java.net.http.HttpResponse?

查找剩余的枚举

更新AWS凭据

try 从REST API返回对象列表时出错

如果按钮符合某些期望,如何修改它的文本?

在处理2个映射表时,没有更多的数据可从套接字读取

与IntArray相比,ArrayList<;Int>;对于大量元素的性能极差

根本不显示JavaFX阿拉伯字母

无法使用Freemarker从XML中读取重复的标记值

Spring Framework6.1中引入的新RestClient是否有适合于测试的变体,就像RestTemplate和TestRestTemplate一样?

Oracle中从JSON中提取和插入数据

为什么创建Java动态代理需要接口参数

try 添加;按流派搜索;在Web应用程序上,但没有;I don’我不知道;It’这个代码错了