Java 通配符有界泛型

标签 java generics

我正在努力解决 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; }
}

假设以下类层次结构:
基础员工(层次结构的顶部),然后
Manager 扩展 Employee,然后
主管延伸经理

下面的代码可以工作,但我不明白为什么允许它。

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(); // OK
Manager ex2 = (Manager) pm2.getSecond(); // OK
Executive ex3 = (Executive) pm2.getSecond(); // why is allowed?

我不明白为什么 Executive 在上面工作,因为它不是父类(super class)型,而是 Manager 的子类型。

是因为Java 8编译器转换了吗? super 经理反对,因此任何事情都会被允许?

最佳答案

如您声明:

Pair<? super Manager> pm2 = ...

Pair接受泛型的方法可以将泛型替换为 Manager及其子类(在您的情况下为 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> 的方法。 .
但在这种情况下,我们希望将未知类型限制为特定类型或父类(super class)型,以防止“放置”可能损害作为参数传递的泛型类型的类型安全性的内容。

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

示例代码来说明:

public void putStuff(Pair<? super Manager> managers) {
    if (...){
       managers.setFirst(new Manager());
    }
    else if (...){
    managers.setFirst(new Executive());
   }
}

现在只有 Manager 的类型或父类(super class)型对于Pair可以传递泛型类型:

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

关于Java 通配符有界泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51706027/

相关文章:

JavaFX:如何同时移动 2 个矩形?

c# - 帮助使用 .NET Generics/Dictionary 替换我的数组

用于类似动态类型转换的 Java 反射/通用类型

java - 有代码重复并使其非常简单/可读更好,还是没有重复(使用泛型)但要复杂得多?

java - 关于捆绑 JRE 的 JSmooth 问题

java - 什么以及为什么是 Java 6 和 Java 7?

java - 如何让 Spring MVC 读取日期格式为 "2019-3-29"的路径参数?

java - 条件为恰好使用 m 个硬币的硬币找零问题

java - 使函数返回与输入类型相同的输出类型

typescript :将 typeof 与泛型结合使用