通用通配符类型不应在返回参数中使用

时间:2014-04-02 14:44:04

标签: java generics

是否可以说通用通配符类型不应该用在方法的返回参数中?

换句话说,声明一个如下所示的接口是有意义的:

interface Foo<T> {
  Collection<? extends T> next();
}

此外,可以说通用通配符类型仅在方法的参数声明时才有意义吗?

4 个答案:

答案 0 :(得分:19)

在方法形式参数中使用通配符类型的主要好处是为用户提供灵活性,例如任何类型的Collection,或List或任何实现Collection的东西(假设该集合声明为Collection<?>)。您经常会发现自己在形式参数中使用通配符类型。

但理想情况下,您应该避免将它们用作方法的返回类型。因为这样,你会强制该方法的用户在调用者端使用通配符类型,即使他们不想这样做。通过使用通配符类型,你会说,嘿!此方法可以返回任何类型的Collection,因此您的工作就是照顾它。你不应该这样做。最好使用有界类型参数。使用有界类型参数,将根据您传递的类型或方法调用的目标类型推断类型。

这是来自 Effective Java Item 28:

的引用
  

不要使用通配符类型作为返回类型。而不是提供   为用户提供额外的灵活性,这将迫使他们使用   客户端代码中的通配符类型   正确使用的通配符类型是   几乎看不到类的用户。他们导致方法接受   他们应该接受的参数并拒绝他们应该拒绝的参数。 如果   一个类的用户必须考虑通配符类型,有   这个类的API可能有问题。

答案 1 :(得分:4)

不,说这个是不可行的。

或者这样说:确实有这样的界面是有意义的。

想象一下以下

interface Foo<T>  
{
    Collection<? extends T> next();
}

class FooInteger implements Foo<Number> 
{
    private final List<Integer> integers = new ArrayList<Integer>();
    void useInternally()
    {
        integers.add(123);
        Integer i = integers.get(0);
    }

    @Override
    public Collection<? extends Number> next() 
    { 
        return integers;
    }
}

// Using it:
Foo<Number> foo = new FooInteger();
Collection<? extends Number> next = foo.next();
Number n = next.iterator().next();

如果您将返回类型写为Collection<T>,则无法返回包含T子类型的集合。

是否需要具有这种返回类型取决于应用案例。在某些情况下,它可能只是必要。但如果很容易避免,那么你就可以做到这一点。


编辑:编辑代码以指出差异,即您可能无法始终在内部选择类型。但是,在大多数情况下,可以避免返回涉及通配符 的内容 - 正如我所说,如果可能的话,应该避免使用。

上面描述的示例仍应被视为示例以强调关键点。当然,虽然这样的实现是一种不好的做法,因为它暴露了内部状态。

在这种情况和类似情况下,人们通常会返回类似

的内容
return Collections.<Number>unmodifiableList(integers);

并且通过这个,将返回类型声明为Colletion<Number>unmodifiableList方法解决了暴露的内部状态的问题,并且具有允许将类型参数更改为超类型的整洁属性,因为列表是......好吧,无论如何都是不可修改的。

答案 2 :(得分:0)

要避免提醒(例如:声纳),请将Class<?>替换为Class<? extends Object>或根本不使用它。只需返回class

答案 3 :(得分:0)

强烈建议不要将通配符类型用作返回类型。由于类型推断规则相当复杂,因此该API的用户不太可能会知道如何正确使用它。 让我们以返回“列表”的方法为例。是否可以在此列表中添加“狗”,“猫” ...……我们根本不知道。编译器也没有,这就是为什么不允许这种直接使用的原因。通配符类型的使用应限于方法参数。

当方法返回通配符类型时,此规则会引起问题。

不兼容的代码示例

  List<? extends Animal> getAnimals(){...}  

兼容解决方案

  List<Animal> getAnimals(){...} 

  List<Dog> getAnimals(){...}