1

当我们想要传递包含子类对象的列表时,我们在方法 args 中使用通配符。但如下所示,我们可以使用 Type 参数实现相同的功能。那么为什么我们需要通配符呢?

场景
假设我们有一个名为Department的基类及其名为Development & Sales的子类。Development & Sales 是 Department 的子类型,但 List 和 List 不是 List 的子类型。 因此,当我们想将 Development 或 Sales 对象列表作为方法 arg 传递时,该方法接受任何类型的部门列表,我们使用通配符。但是在代码中我们可以看到我们可以在不使用通配符的情况下实现相同的效果。

根据 Effective Java 在返回类型中使用通配符确实是一个糟糕的选择。通配符真正有用的其他用例是什么?

class MyGenericsClass<T extends SuperClass> {

    //These 2 methods works the same
    <H> void unboundedMethod1(AnotherGenericClass<H> arg) {
    }
    void unboundedMethod2(AnotherGenericClass<?> arg) {
    }

    //These two methods works the same
    <H extends SuperClass> void boundedMethod1(AnotherGenericClass<H> arg) {
    }   
    void boundedMethod2(AnotherGenericClass<? extends SuperClass> arg) {
    }   

    //These two methods works the same
    <U extends Building> void boundedListMethod1(List<U> list){
    }
    void boundedListMethod2(List<? extends Building> list) {
    }
    
    //Why can't we write like this? Giving Compile time error
    //<U> void notWorkingMethod1(List<U extends SuperClass> list){ //Statements }
    //<T> void notWorkingMethod2(List<U extends SuperClass> list){ //Statements }
}

在 notWorkingMethods1 和 notWorkingMethods2 内部,为什么我们不能直接传递 Bounded Type 参数,但我们可以通过在返回类型之前先声明它来做到这一点?

4

1 回答 1

3

首先,您最初认为这两种方法行为相同的假设是不正确的。

假设泛型类是列表。尝试添加一些类型H的东西List<H>和任何东西List<?>,看看它们的行为是否相同。

关于最后一个问题。

<U extends Building> void boundedListMethod1(List<U> list)

说 U 是扩展 Building 的类型,而 List 包含该类型。

然而,

<U> void notWorkingMethod1(List<U extends Building> list)

说有一些 typeU和一个 List 需要一个 type U that extends Building。这两个陈述并不意味着兼容性。U 可能不是 Building 的子类,但 List 期望它。

当您只想做某事而不考虑类型时,通配符很有帮助。

List<Map<String,Integer>> list = ....

for (Map<?,?> m : list) {
   System.out.println(m);
}

它们对于复制类型也很有用。

public <H> void copy(List<? extends H> src, List<? super H> dst) {
   for (H a : src) {
       dst.add(a);
   }
}
于 2020-08-09T13:34:24.853 回答