为什么将变量声明为通配符类型

Vic*_*yew 5 java generics wildcard

Java教程中,有时会这样写:

Set<?> unknownSet = new HashSet<String>();
Run Code Online (Sandbox Code Playgroud)

虽然我了解在类定义和方法中使用类型参数和通配符的好处,但我想知道以下问题:

  • 为变量指定包含通配符的类型有什么好处?
  • 在现实生活中,人们会这样做吗?什么时候这样做?

And*_*ner 3

通配符仅在方法参数声明中真正有用,因为它们增加了可接受的参数类型的范围,例如:

\n\n
void original(List<Number> list) { /* ... */ }\nvoid withUpperWildcard(List<? extends Number> list) { /* ... */ }\nvoid withLowerWildcard(List<? super Number> list) { /* ... */ }\n\noriginal(new ArrayList<Number>());       // OK.\noriginal(new ArrayList<Integer>());      // Compiler-error.\noriginal(new ArrayList<Object>());      // Compiler-error.\n\nwithUpperWildcard(new ArrayList<Number>());  // OK.\nwithUpperWildcard(new ArrayList<Integer>());  // OK.\n\nwithLowerWildcard(new ArrayList<Number>());  // OK.\nwithLowerWildcard(new ArrayList<Object>());  // OK.\n
Run Code Online (Sandbox Code Playgroud)\n\n

返回类型中的通配符使您的类的用户的生活变得困难(或者更确切地说,混乱),因为您必须传播它们,或者执行显式工作以使它们消失,例如:

\n\n
List<? extends Number> method() { /* ... */ }\n\n// Compiler error.\nList<Number> list1 = method();\n// OK, but yuk!\nList<? extends Number> list2 = method();         \n// OK, but the list gets copied.\nList<Number> list3 = new ArrayList<Number>(method());  \n
Run Code Online (Sandbox Code Playgroud)\n\n

局部变量中的通配符不是必需的(除非接受通配符返回方法的结果)。

\n\n

引用《Effective Java》第二版:

\n\n
\n

如果类的用户必须考虑通配符类型,则 class\xe2\x80\x99s API 可能有问题。

\n
\n