【问题标题】:On Java generics lower bound usage: ? super T [duplicate]关于 Java 泛型的下限用法: ?超级T [重复]
【发布时间】:2018-04-10 09:09:12
【问题描述】:

我试图深入了解下限通配符的用法。我正在尝试编写一个通用方法copy,它将一个List 的内容复制到另一个。我想出了这个方法签名:

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

我认为这个签名很全面,可以解决所有场景。但是,我看到在 Java Collections 类中,方法签名是这样的:

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

我不明白他们为什么使用List&lt;? super T&gt; dest 而不仅仅是List&lt;T&gt; dest。他们的签名是否有一些额外的灵活性?

【问题讨论】:

  • 你可以用反引号包围内联代码,以避免 HTML 吃掉你的泛型。

标签: java generics


【解决方案1】:

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

没有像 Eran 那样指定类型见证,两种方法在灵活性上没有区别。

从本质上讲,? super T 而非 T 的使用只是一种风格上的差异,但它是更好的做法,这可以通过应用一些良好代码的原则来看出:

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

Java tutorials 也推荐使用? super T(他们甚至使用copy 函数):

出于本次讨论的目的,将变量视为提供以下两种功能之一会很有帮助:

一个“入”变量
“in”变量为代码提供数据。想象一个带有两个参数的copy 方法:copy(src, dest)src 参数提供了要复制的数据,所以它是“in”参数。

“输出”变量
“out”变量保存在其他地方使用的数据。在copy 示例copy(src, dest) 中,dest 参数接受数据,因此它是“out”参数。

在决定是否使用通配符以及哪种类型的通配符合适时,您可以使用“入”和“出”原则。以下列表提供了要遵循的准则:

通配符指南:

  • “in”变量使用上限通配符定义,使用 extends 关键字。
  • “out”变量定义为下界 通配符,使用 super 关键字。

【讨论】:

  • 这个问题是also answered here。我认为显示它们等效的所有情况的示例特别令人信服。 (由于赏金,无法关闭。)
  • @River:最好用一个 mod 标志来标记它,解释它是骗子而不是回答它。
  • @Makoto 稍后发现了副本
【解决方案2】:

这是一个例子:

以下 sn-p 使用签名 &lt;T&gt; void copy(List&lt;? super T&gt; dest, List&lt;? extends T&gt; src) 通过编译,但不适用于签名 &lt;T&gt; void copy(List&lt;T&gt; dest, List&lt;? extends T&gt; 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);

【讨论】:

  • 上面的代码sn-p通过两个签名的编译。刚刚在 Eclipse 中检查过。
  • @user496934 奇怪。我还在 Eclipse 上对此进行了测试,得到了The parameterized method &lt;HashMap&lt;String,String&gt;&gt;copy(List&lt;HashMap&lt;String,String&gt;&gt;, List&lt;? extends HashMap&lt;String,String&gt;&gt;) of type YourClass is not applicable for the arguments (List&lt;Map&lt;String,String&gt;&gt;, List&lt;HashMap&lt;String,String&gt;&gt;)
  • @user496934 您是拨打了obj.&lt;HashMap&lt;String,String&gt;&gt;copy (lm,lhm); 还是只是拨打了obj.copy (lm,lhm);
  • 这样编造一个例子很容易,但完全不现实。我还是很好奇有什么实际用途。
  • 但这只是因为您指定了显式类型见证,这不是其中一种情况的正确类型见证。这并不能反驳两个声明在不使用类型见证时接受相同可能的参数集的说法。
猜你喜欢
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 2013-04-02
  • 2022-08-14
  • 2014-12-11
相关资源
最近更新 更多