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

Java 返回参数中不应使用泛型通配符类型,java,generics,Java,Generics,在方法的返回参数中不应使用泛型通配符类型是否可行 换句话说,声明如下接口是否有意义: interface Foo<T> { Collection<? extends T> next(); } 接口Foo{ 集合使用通配符类型(例如在方法形式参数中)的主要好处是为用户提供传递的灵活性,例如任何类型的集合,或列表或任何实现集合的内容(假设集合声明为集合)。您经常会发现自己在形式参数中使用通配符类型 但理想情况下,您应该避免将它们用作方法的返回类型。因为这样,您将强制该方

在方法的返回参数中不应使用泛型通配符类型是否可行

换句话说,声明如下接口是否有意义:

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

集合使用通配符类型(例如在方法形式参数中)的主要好处是为用户提供传递的灵活性,例如任何类型的
集合
,或
列表
或任何实现集合的内容(假设集合声明为
集合
)。您经常会发现自己在形式参数中使用通配符类型

但理想情况下,您应该避免将它们用作方法的返回类型。因为这样,您将强制该方法的用户在调用端使用通配符类型,即使他们不想这样做。通过使用通配符类型,您的意思是,嘿!此方法可以返回任何类型的
集合
,因此您的工作就是处理这一问题。您不应该这样做。最好使用bounded type parameter。使用bounded type parameter,将根据您传递的类型或方法调用的目标类型推断类型

下面是对Java第28条的引用:

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


不,这样说是不可行的

或者这样说:拥有这样一个界面是有意义的

想象一下

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
unmodifiableList
方法解决了暴露的内部状态的问题,并且具有允许将类型参数更改为超类型的简洁属性,因为该列表……无论如何都是不可修改的。

强烈建议不要将通配符类型用作返回类型。 由于类型推断规则相当复杂,因此 该API的用户将知道如何正确使用它
返回“列表”的方法示例实际上,即使我将返回类型声明为集合,也可以返回包含T的子类型元素的集合:
final Collection arrayList=new arrayList();arrayList.add(new Integer(0));
@jilt3d添加了一个解释作为编辑查看编辑后的示例,我仍然看不出为什么用通配符声明返回类型有意义?@jilt3d集合在内部声明为
列表
。如果返回类型必须是
集合
,则无法从该方法返回它是
CollectionWell,您可以将内部集合声明为
private final List integers=new ArrayList();
,并且仍然可以添加
Integer
实例。是的,这次调用get()(而不是
Integer
)时,您将获得一个
数字但在现实世界中,无论如何这是最好的。因此,正如我所理解的——如果我在不使用通配符的情况下声明返回类型,我不会失去任何灵活性,这只会使接口的使用更加困难?否则,我能想到的唯一优势是它将“锁定”"返回的集合,并将使其具有某种不可变性,因为我们不允许向使用通配符引用的集合中添加任意元素。@jilt3d不可变是完全不同的事情。使用有界类型参数更愿意提供类型安全性。您仍然可以添加与集合类型兼容的元素n、 @jilt3d关于“不变性”(我在编辑我的答案时也提到了这一点):关于向集合中添加新元素的可能性,这是正确的。但通常情况下并非如此:您仍然可以添加
null
,或者只需对返回的集合调用
collection.clear()
。例如,同意“不适应性".你能编辑你的第一段吗?这样我就可以接受答案-当你使用
集合
作为正式参数,假设
T
字符串
,你仍然可以通过
列表
。在这种情况下使用通配符的主要好处是,我可以通过像
列表
这样的集合进行考试ple(如果我们假设
MyString扩展了String
)@jilt3d Yes.BTW,
String
是最后一个类。它不能扩展:)我想强调一点,因为我认为它在一个明显的地方没有得到很好的解决,那就是集合上的通配符不会使该集合不可变。我们可以从集合中删除元素,我们可以向集合中添加
null
,然后。如果它是一个列表,那么我们还可以更改元素的顺序(这只是抛开能够丢弃通配符的问题不谈了。)引用来源而不提及来源被认为是不礼貌的。因此,诚实地说,这是你从中复制的解释。@JacobvanLingen谢谢你提醒我。我已经更新了来源。:)
return Collections.<Number>unmodifiableList(integers);
  List<? extends Animal> getAnimals(){...}  
  List<Animal> getAnimals(){...}    or

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