为了账号安全,请及时绑定邮箱和手机立即绑定

Java 通配符有界泛型

Java 通配符有界泛型

森栏 2021-06-28 20:26:24
我正在努力使用 Java 8 通配符泛型。假设一个泛型类(来自 Core Java 书籍)称为 Pair<T>class Pair<T> {    private T first;    private T second;    public Pair() {        first = null;        second = null;    }    public Pair(T first, T second) {        this.first = first;        this.second = second;    }    public T getFirst() { return first; }    public T getSecond() { return second; }    public void setFirst(T newValue) { first = newValue; }    public void setSecond(T newValue) { second = newValue; }}假设有以下类层次结构:base Employee(层次结构的顶部),然后Manager扩展Employee,然后Executive扩展Manager下面的代码有效,但我不明白为什么允许它。Pair<? super Manager> pm2 =     new Pair<>(      new Employee(1,"Yuri"), // Employee is super of Manager      new Executive()); // Executive is not super of Manager // why Executive is allowed in above Pair<T> ?Employee ex1 = (Employee) pm2.getFirst(); // OKManager ex2 = (Manager) pm2.getSecond(); // OKExecutive ex3 = (Executive) pm2.getSecond(); // why is allowed?我不明白为什么 Executive 在上面工作,因为它不是超级类型,而是经理的子类型。是因为 Java 8 编译器会转换吗?超级店长到对象,所以任何事情都会被允许?
查看完整描述

1 回答

?
MMTTMM

TA贡献1869条经验 获得超4个赞

当您声明时:


Pair<? super Manager> pm2 = ...

Pair接受泛型的方法可以替换泛型 byManager和它的子类(在您的情况下Executive)。


所以从逻辑上讲,当您使用泛型调用方法时,您将得到以下结果:


Pair<? super Manager> pm2 = ...;        

pm2.setFirst(new Executive());  // compile

pm2.setFirst(new Manager());  // compile

pm2.setFirst(new Employee()); // doesn't compile

最后就像你没有使用任何通配符:


Pair<Manager> pm2 = ...;        

pm2.setFirst(new Executive());  // compile

pm2.setFirst(new Manager());  // compile

pm2.setFirst(new Employee()); // doesn't compile

因此,在您的示例中,您使用的下限通配符是无助的。

事实上,它是最糟糕的,因为您将它用于从泛型类型中放入和获取东西,而下界通配符旨在放入东西,而不是从中获取东西。

而您必须执行的强制转换会破坏通用目的(类型安全):


Employee ex1 = (Employee) pm2.getFirst(); // OK

Manager ex2 = (Manager) pm2.getSecond(); // OK

Executive ex3 = (Executive) pm2.getSecond(); // why is allowed?

那么我们需要如何使用Pair<? super Manager>呢?

因为我们希望泛型集合Pair可以分配给其他Pair类型以“放入”东西。

非常常见的用例是声明一个接受泛型类型的方法<? super>。

但在这种情况下,我们希望将未知类型限制为特定类型或超类型,以防止“放置”可能危及作为参数传递的泛型类型的类型安全的东西。


例如,假设您需要一个接受 a PairofManager实例并将事物放入 this 的方法Pair。您不希望客户端方法可以传递 aPair<Executive>否则如果我们添加 a 可能会破坏通用安全性Manager,因为 aManager不是Executive实例所必需的。这里是下界通配符的主要作用。


示例代码来说明:


public void putStuff(Pair<? super Manager> managers) {

    if (...){

       managers.setFirst(new Manager());

    }

    else if (...){

    managers.setFirst(new Executive());

   }

}

现在只有类型或超类型Manager的Pair泛型类型可以传递:


putStuff(new Pair<Manager>(...)); // compile

putStuff(new Pair<Employee>(...)); // compile

putStuff(new Pair<Executive>(...)); // doesn't compile


查看完整回答
反对 回复 2021-06-30
  • 1 回答
  • 0 关注
  • 162 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信