【问题标题】:Generic vs wildcard unknown types通用与通配符未知类型
【发布时间】:2015-03-21 03:22:13
【问题描述】:

建议什么时候做:

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

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

看起来它们都可以正常工作。

【问题讨论】:

  • This reflects the fact that the type parameter is not being used to express any kind of interdependency between the type(s) of the argument(s), the return type and/or throws type. In the absence of such interdependency, generic methods are considered bad style, and wildcards are preferred. Java 语言规范 8 §4.5.1-2。基本上,如果对方法之外的类型存在依赖关系,则应使用第一个。否则,使用第二个。

标签: java generics wildcard


【解决方案1】:

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

例如,您在类型化类 C&lt;K extends String&gt; 中使用它

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

会引发编译器错误。但是为什么有人愿意这样做……

很好的问题,即使答案很可能是相同的。

【讨论】:

    【解决方案2】:

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

    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);
    

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

    【讨论】:

    【解决方案3】:

    将泛型类型明确命名为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

    【讨论】:

      【解决方案4】:

      泛型和通配符未知类型的区别:

      • 在方法参数类型上强制建立关系(使用泛型)
      • 支持多个边界(使用泛型)
      • 支持上限和下限(使用通配符)

      相关问题:

      When to use generic methods and when to use wild-card?

      【讨论】:

        【解决方案5】:

        当您只需要从列表中检索时使用? extends

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

        当您只需要添加到列表时使用? 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:我们不知道 List 的确切类型,但我们可以从中检索到 User
        • ? super User:我们不知道 List 的确切类型,但我们可以在里面放一个 User
        • E extends User:我们不一定知道 List 的确切类型,但它符合以下约束:
          • 我们将其实际类型命名为 E
          • 我们知道E 至少是User
          • 我们既可以从 List 中检索 E,也可以将 E 放入 List。

        另见:

        【讨论】:

        • 这应该是公认的答案。它是唯一真正以正确方式回答问题的人。其他人都读到“我不知道,但这可能发生,也可能不是谁真正知道?”。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-30
        • 2020-03-20
        • 2018-04-21
        • 2013-09-03
        • 2014-05-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多