2017-10-29 19 views
10

我想了解一些深度的下界通配符的用法。我正在尝试编写一个通用方法copy,它将一个List的内容复制到另一个。我想出了这个方法签名:关于Java泛型下限用法:? super T

<T> void copy(List<T> dest, List<? extends T> src) 

我觉得这个签名是全面解决所有的场景。但是,我看到,在Java集合类的方法签名是这样的:

<T> void copy(List<? super T> dest, List<? extends T> src) 

我不明白为什么他们使用List<? super T> dest,而不是只是List<T> dest。他们的签名是否有一些额外的灵活性?

+0

您可以用反引号包围内联代码以避免HTML占用您的泛型。 –

回答

1

下面是一个例子:

下面的代码片段通过编译与签名<T> void copy(List<? super T> dest, List<? extends T> src),但不与签名<T> void copy(List<T> dest, List<? extends T> src)工作:

YourClass obj = new YourClass(); 
List<HashMap<String,String>> lhm = new ArrayList<>(); 
List<Map<String,String>> lm = new ArrayList<>(); 
obj.<HashMap<String,String>>copy (lm,lhm); 
+0

上面的代码片段通过了两个签名的编译。只是在Eclipse中检查它。 – user496934

+0

@ user496934奇怪。我也在Eclipse上测试了这个,并得到了类型为YourClass的参数化方法> copy(List >,List <?extends HashMap >)适用于参数(List >)' – Eran

+1

@ user496934您是否调用了obj。> copy(lm,lhm );'或者只是'obj.copy(lm,lhm);'? – Eran

5

有没有明确的类型证人没有实际的区别。

没有指定Eran所做的类型见证,两种方法在灵活性方面没有区别。

从本质上讲,在T使用? super T只是一个风格的差异,但它是更好的做法,因为可以通过应用一些好的代码原则中可以看出:更明确地? super T

  • 明确意图显示dest应该采用哪种类型。
  • Modularity:您根本不需要查看src上的类型约束,以知道dest可以采用哪些类型。
  • Producer Extends, Consumer Super (PECS):生产者参数(下面的“in”)应该使用extends,而消费者参数(下面的“out”)应该使用super关键字。

使用? super T还建议由Java tutorials(他们甚至使用copy功能):

为了讨论的目的,有利于思考的变量提供两种功能之一:

“In”变量
“in”变量向代码提供数据。想象一下带有两个参数的copy方法:copy(src, dest)。参数src提供要复制的数据,因此它是“in”参数。

一个“输出”变量
一个“输出”变量保存数据供别处使用。在copy示例中,copy(src, dest),dest参数接受数据,因此它是“out”参数。

在决定是否使用通配符以及适用的通配符类型时,可以使用“in”和“out”原则。以下列表提供的准则遵循:

通配符准则:

  • 的“中的”变量定义与上界通配符,使用 extends关键字。
  • 使用super关键字定义了一个“out”变量,其下界为 通配符。
+0

这个问题[也在这里回答](https://stackoverflow.com/questions/34985220/differences-between-copylist-super-t-dest-list-extends-t-src-and-co)。我认为这个例子显示了所有相同的情况,这一点特别令人信服。 (因为赏金而无法关闭。) – River

+0

@河流:这可能会更好地用一个国防部标志来解释这是一个愚蠢的行为,而不是回答它。 – Makoto

+0

@Makoto稍后发现重复 – River