【问题标题】:Simple Java generics question简单的 Java 泛型问题
【发布时间】:2010-09-26 18:58:30
【问题描述】:

我想要一个方法来计算 Integer、Double 和 Float 类型的 LinkedList 的平均值。

问题在于sum += i; 语句,因为java 表示没有为Object 类型定义+ 运算符。

我可以进行强制转换,但如果 LinkedList 是浮点类型,例如,并且强制转换是整数,我就不会计算正确的平均值。

我该怎么办?谢谢。

 public double mean (LinkedList<?> l)
 {
  double sum = 0;
  int n = 0;
  for (Object i : l)
  {
   n++;
   sum += i;
  }

  return sum / n;
 }

【问题讨论】:

  • 您不应该需要LinkedList,因为您所做的一切都是在迭代l 中的元素。只需使用Iterable&lt;? extends Number&gt;

标签: java generics


【解决方案1】:

您应该将您的列表限制为Numbers。这是IntegerFloatDouble 和其他数字类型的通用超类。它没有定义运算符,只有转换方法,例如double,但这对你来说已经足够了:

 public double mean (LinkedList<? extends Number> l)
 {
  double sum = 0;
  int n = 0;
  for (Number i : l)
  {
   n++;
   sum += i.doubleValue();
  }

  return sum / n;
 }

【讨论】:

  • 这整个&lt;? extends Number&gt; 发生在我不使用 Ruby 的时候。这个结构叫什么?这个语法LinkedList&lt;?&gt; 是否表示我们有一个未知类型的 LL,而LinkedList&lt;? extends Number&gt; 是一个未知类型的 LL,每个类型都保证是 Number 的子类?
  • 为什么不LinkedList &lt;Number&gt;
  • 回答你的第一个问题:是的,使用LinkedList&lt;?&gt; 指定一个包含未知类型元素的链表(它们至少是对象),LinkedList&lt;? extends Number&gt; 可能包含 Number 的任何子类型的元素(和如果没有人在做奇怪的反射黑客,它保证)。为什么不使用LinkedList&lt;Number&gt;?它将您的 api 的用户与特定类型联系起来。您不能传入LinkedList&lt;Integer&gt;。事实上,甚至不需要 LinkedList,最好的方法是要求 Iterable&lt;? extends Number&gt;
  • @Tony,这被称为 带有扩展的通配符LinkedList&lt;? extends Number&gt; 匹配 Number 的子类的任何列表。 IE。它可以是LinkedList&lt;Number&gt;LinkedList&lt;Integer&gt;LinkedList&lt;Double&gt; 等。重要的是要注意后者是 not 的子类 LinkedList&lt;Number&gt; - 这就是为什么这里需要通配符。
  • @Willi,如果您想反映其他人的评论,建议在您的回答中包含他的昵称,前面有一个@(例如@Tony) - 否则他不会收到有关您的通知评论。
【解决方案2】:

唯一的选择是泛化java.lang.Number,但它实际上并没有多大帮助,因为您不能将数字拆箱到任何可以应用于原始算术运算符的东西。因此,您仍然需要检查每个 Number-types 并在 Number-object 上调用 Number.doubleValue、intValue 等。

【讨论】:

    【解决方案3】:
    public <T extends Number> double mean (LinkedList<T> l) {
      double sum = 0;
      int n = 0;
      for (T i : l)  {
        n++;
        sum += i.doubleValue();
      }
    
      return sum / n;
    }
    

    【讨论】:

    • 看起来与彼得的回答极为相似。
    • Aham...真聪明...你有没有想过我 c&p 这个问题 sn-p 并编辑它?
    • 我做了,但您编辑的唯一内容是没有为彼得提出的答案增加任何价值。使用只有一个参数的泛型方法是没有用的。
    • 其实你看发帖时间,我之前发过。实际上,在 3 分钟前……
    【解决方案4】:

    在 Java 中,泛型集合是逆变的。这意味着如果您有父类 A 和扩展 A 的 B 类,那么您不能制作像 List&lt;A&gt; list = new LinkedList&lt;B&gt;(); 这样的东西。

    但是有可能允许这种类型的替换:您可以使用像List&lt;? extends A&gt; list = new LinkedList&lt;B&gt;(); 这样的结构。对于您的情况:

     public double mean (List<? extends Number> l)
     {
      double sum = 0;
      int n = 0;
      for (Object i : l)
      {
       n++;
       sum += i;
      }
    
      return sum / n;
     }
    

    【讨论】:

    • 不会编译。没有为对象定义 + 运算符。
    【解决方案5】:

    这里有几件事需要考虑。

    1. 允许收集而不是仅列出列表
    2. 您不需要单独的变量“n”,只需使用 l.size()
    3. 注意空/空输入

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-04
      • 1970-01-01
      相关资源
      最近更新 更多