是否可以说通用通配符类型不应该用在方法的返回参数中?
换句话说,声明一个如下所示的接口是有意义的:
interface Foo<T> {
Collection<? extends T> next();
}
此外,可以说通用通配符类型仅在方法的参数声明时才有意义吗?
答案 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(){...}