Java:泛型和lambda表达式

nvbavucw  于 2023-05-15  发布在  Java
关注(0)|答案(2)|浏览(172)

这看起来很基本,但我不明白为什么我的代码编译不了。
我有一个class Person,它有一个String name属性和一个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());

我不明白为什么

djmepvbi

djmepvbi1#

您的代码无法编译的原因是您定义了startsA()方法来返回扩展Person的通配符类型的Predicate。通配符类型表示Person的未知子类型,
更改startsA()方法以返回Predicate<Person>而不是使用通配符类型:

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

toe950272#

泛型是一个 meta级别删除。你需要站在编译器的Angular 去理解它们。
我经常看到泛型的错误,也是你似乎犯的错误,就是你认为Predicate<? extends Person>的意思是“这是一个可以测试任何人的 predicate ”。一个雇员,一个客户-不重要,因此,“无论什么扩展人”的权利。
”””但这并不是它的意思。
毕竟,想象一下它的意思。什么是Predicate<Person>?一个 predicate 只能专门测试new Person()而不能测试new Employer()?Java并不是这样工作的--任何Employer的示例都可以被用作Person,所以这将是非常奇怪的。
实际上,Predicate<Person>在这里的意思是:可以测试任何人的 predicate 宾语。
Predicate<? extends Person>是什么意思这一点:
一个 predicate 可以测试。。我不知道它能检测什么。我所知道的是,不管它是什么,它是Person或其子类型的某种类型。
那这样做有什么意义呢?在这个特定的情况下(对于 predicate ),并不是那么多。让我们想想列表。我们有3种不同的相关类型(记住,Integer和Double都扩展了Number,Number扩展了Object)

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

您可以将List<Integer>对象传递给接受List<? extends Number>的方法。你不能把它传递给一个接受List<Number>的方法。为什么不呢- Integer可以扩展Number,对吧?啊,但是在泛型中,这是不变的,就像,不,你不能只是用它的子类型替换类型。毕竟,我可以将Double对象添加到List<Number>。我可以在列表中添加Number对象,Double对象就是Number对象,QED。
但是,将Double对象添加到List<Integer>,这并不好。因此,需要一个List<? extends Number>-尝试一下,你不能**向这样的列表添加东西。出于同样的原因:List<? extends Number>并不意味着:“一个可以保存数字的列表-任何数字”。恰恰相反。它的意思是:“一个可以容纳...我不知道它能装什么(因此有问号!我所知道的是,无论它持有什么,它都是数字。或Number的任何子类)。鉴于此,list.get(5)将返回Number类型的表达式(鉴于我们所知道的一些事情,这是安全的),但您不能向其添加任何内容(除了字面量null的学术情况,这是所有类型)。
特别是对于PredicatePredicate<? extends>是完全无用的,在任何情况下都不应该出现。Predicate<? super X>可以非常方便。毕竟,这意味着:“一个 predicate 可以测试..我不知道它能测试什么。我所知道的是,它要么是X,要么是X的某种超级类型。有了这些信息,.test(instanceOfX)就可以了。

相关问题