繁体   English   中英

通用vs通配符未知类型

[英]Generic vs wildcard unknown types

什么时候建议做:

public <E> boolean hasPropertyX(List<E extends User> alist);

public boolean hasPropertyX(List<? extends User> alist);

看起来它们的效果也一样好。

没有类型返回值,我能想到的唯一区别是在方法调用期间显式输入第一种声明方式。

例如,您在类型C<K extends String>中使用它

List<V extends String> input = ...;
boolean var = obj.hasProperty<K>(input);

会引发编译错误。 但是为什么有人想要这样做......

很好的问题,即使答案很可能两者都是一样的。

明确地将泛型类型命名为E而不是? 有这些用途(据我所知):

0)将返回类型绑定到参数类型的某些部分 - 例如:

public <E> E getSomeElement(List<E> lst) { ... }
// ^ If we don't name the argument type as having E,
// then we can't specify the return type as being E

1)将参数类型的某些部分绑定到封闭类型的某些部分:

class Storage<E> {
    E item;
    public void replace(Storage<E> st) { item = st.item; }
    // ^ This wouldn't work if we wrote Storage<?> instead
}

2)绑定参数类型,返回类型和封闭类型的一些组合 (参见#0和#1)。

我们可以逃脱匿名类型名称? 如果我们不关心实际类型。 这是一个基本的例子:

boolean allEqual(List<?> lst, Object y) {
    for (Object x : lst) {  // Any reference can be stored as Object
        if (!y.equals(x))  // equals takes an Object
            return false;
    }
    return true;
}
// ^ We could also rewrite this example with List<E> and "E x".

另一个例子:

int intSum(List<? extends Number> lst) {
    int sum = 0;
    for (Number x : lst)  // We only care that the list element is a Number
        sum += x.intValue();
    return sum;
}
// ^ We could also rewrite with List<E extends Number> and "E x".

备选阅读: http//docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

我想在那个特定的例子中,它们在类型检查方面都以相同的方式有效地工作。 但是,如果将泛型类型扩展为需要某个类的基类或超类,则它可能很有用。 例如

public <E extends User> boolean hasPropertyX(List<E> alist);

这至少强制您接收一些User子类。

编辑

您可以使用通配符来实现相同的功能:

public boolean hasPropertyX(List<? extends User> alist);

但是,例如,如果要将泛型用于多个参数,则无法执行此操作:

public <E extends Automobile> void crashAutos(List<E> list1, List<E> list2);

这会对两个参数强制执行泛型类型,而以下代码不会强制两个列表包含相同的类型:

public void crashAutos(List<? extends Automobile> list1, List<? extends Automobile> list2);

我可以使用Automobile类的两个不同子类调用该方法:

List<Car> cars = ...
List<Truck> trucks = ...
crashAutos(cars, trucks);

而使用泛型对两个参数强制执行相同的类型。

泛型和通配符未知类型之间的差异:

  • 在方法参数的类型上实现关系(使用泛型)
  • 支持多边界(使用泛型)
  • 支持上限和下限(使用通配符)

相关问题:

何时使用通用方法以及何时使用通配符?

? extends 当您只需要从List中检索? extends

User getElement(List<? extends User> list, int i) {
    return list.get(i);
}

? super 当你只需要添加到List时? super

void addElement(List<? super User> list, User u) {
    list.add(u);
}

使用E extends ,当你需要检索并添加:

<E extends User> void swapElements(List<E> list, int i, int j) {
    E temp = list.get(i);
    list.set(i, list.get(j));
    list.set(j, temp);
}
  • ? extends User ? extends User :我们不知道List的确切类型,但我们可以从中检索User
  • ? super User ? super User :我们不知道列表的确切类型,但我们可以将User放入其中。
  • E extends User :我们不一定知道List的确切类型,但它符合约束,例如:
    • 我们给它的实际类型命名为E
    • 我们知道E至少是User
    • 我们都可以从List中检索E并将E放入List中。

也可以看看:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM