【问题标题】:Upper bounded generics VS superclass as method parameters?上限泛型VS超类作为方法参数?
【发布时间】:2014-01-27 20:12:24
【问题描述】:

据我所知,使用上限泛型和使用超类作为方法参数都接受相同的可能参数。哪个是首选,两者之间有什么区别(如果有的话)?

上界泛型作为参数:

public <T extends Foo> void doSomething(T foo) {}

超类作为参数:

public void doSomething(Foo foo) {}

【问题讨论】:

    标签: java generics


    【解决方案1】:

    这是一个上限类型参数。下限是使用super 创建的,对于类型参数,您实际上无法做到这一点。 You can't have a lower bounded type parameter

    如果你想传递一个List&lt;T&gt;,那会有所不同。所以,对于以下两种方法:

    public <T extends Foo> void doSomething(List<T> foos) {}
    public void doSomething(List<Foo> foo) {}
    

    对于给定的类:

    class Bar extends Foo { }
    

    以下方法调用:

    List<Bar> list = new ArrayList<Bar>();
    doSomething(list);
    

    对第一种方法有效,但对第二种方法无效。第二种方法失败,因为List&lt;Foo&gt; 不是List&lt;Bar&gt; 的超类型,尽管FooBar 的超类型。但是,第一种方法通过了,因为那里的类型参数T 将被推断为Bar

    【讨论】:

    • 我明白了。有任何理由使用超类作为参数吗?还是只是在可能的情况下使用它?
    • @Someone 当您只传递Foo 类型或其子类型的单个参数时,您不需要泛型方法。您可以将Foo 的子类的实例传递给Foo 的参数类型。
    • 这回答了一个不同的问题。在原始问题中,FooT 的超类型。而在您的情况下,List&lt;Foo&gt; 不是List&lt;T&gt; 的超类型,所以这就是它不同的原因。在您的情况下,List&lt;T&gt; 的超类型将改为 List&lt;? extends Foo&gt;
    【解决方案2】:

    一般来说,只有在类/方法/字段声明中的多个位置使用类型变量时,您才需要它。当您在方法(而不是类)上声明一个时,唯一可以使用它的地方是该方法的参数和返回值。

    例如,您可以在多个参数上使用它以确保它们的类型匹配:

    public static <T> void addToList(List<T> list, T element) {
        list.add(element);
    }
    

    这是一个简单的例子,但你可以看到它阻止你给它一个与列表的泛型类型不匹配的元素:

    List<Integer> list = new ArrayList<>();
    addToList(list, 7);
    //addToList(list, 0.7); // doesn't compile
    //addToList(list, "a"); // doesn't compile
    

    你也可以将参数和返回类型声明为同一类型:

    public static <T> T nullCheck(T value, T defValue) {
        return value != null ? value : defValue;
    }
    

    由于此方法返回给定的两个T 对象之一,我们可以肯定地说返回的对象也是T 类型。

    Integer iN = null;
    Integer i = nullCheck(iN, 7);
    System.out.println(i); // "7"
    
    Double dN = null;
    Double d = nullCheck(dN, 0.7);
    System.out.println(d); // "0.7"
    
    Number n = nullCheck(i, d); // T = superclass of Integer and Double
    System.out.println(n); // "7"
    

    对于问题中的示例,类型变量只使用一次,因此相当于使用超类。在这种情况下,您应该避免声明类型变量,这只是不必要的混乱。

    另外我应该注意,另一个答案将示例更改为使用List&lt;T&gt;List&lt;Foo&gt;,但正如 cmets 中所述,超类实际上是List&lt;? extends Foo&gt;,因此那里也不需要类型变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多