参数的通用类型,也是返回值

时间:2011-02-07 00:36:43

标签: java generics

我有一个像这样的非通用代码:

class List {
  List intersect(List out, List other) {
    if (out == null) out = new List();
    // insert elements common to $this and $other into $out
    return out;
  }
}

该方法可安全地与包含对象的混合类型一起使用:

  1. other可以包含更具体类型的对象(子类)
  2. out可以包含特定类型较少的对象(超类)
  3. E.g。 (不是来自真实的代码)

    List<Number> my;
    List<Integer> other;
    List<Object> result = new();
    
    result = my.intersect(result, other);
    

    因此我需要的是:

    class List<T> {
      <R super T> List<R> intersect(List<R> out, List<? extends T> other);
    }
    

    但是这不能编译。泛型常见问题解答声明类型参数的下限没有意义但我在上面的示例中看不到它。

    我最接近的是:

    List<? super T> intersect(List<? super T> out, List<? extends T> other);
    

    但这需要在呼叫站点显式转换返回值。

    是否有可能以对所有现有用途类型安全的方式对此方法进行一致化?

    更新 如果不明显:这不是java.util.List(它是一个接口btw。),而是一个自定义类。省略了不相关的部分,但方法签名完全如图所示(访问级别除外)。

    UPDATE2: 通过类型安全,我的意思是尽可能地限制。理想情况下,所有参数都应遵守上述规则。

3 个答案:

答案 0 :(得分:0)

你试图打破协方差和逆变的规则。假设您希望List<Object>作为out参数而T是某个A类,并且还有一些其他B类扩展A.您的intersect方法的实现者会创建一个{{ 1}}对于List<A>,这看起来很好,因为A扩展了B.但是调用者获得了一个他认为是out的列表。现在调用者试图插入一堆C(与A和B无关,除了所有三个都在某个时候从Object派生)并且整个事情都爆炸了。

换句话说,这是不可能的。

答案 1 :(得分:0)

编辑:由于我完全误解了这个问题,所以这里有了一个新的答案。

我首先要回答

class List<T> {
      /**
       * Creates the intersection of this list with a second list,
       * adding the resulting elements to another list.
       * @param out the List to which the output should be added.
       *     If null, a new List will be created.
       * @param second the second list to intersect with this list.
       * @return out, with the intersection of left an right added
       */
   <R super T, S extends R>
      List<R> intersect(List<R> out, List<S> second);
}

但是你发现它没有编译。 是的,我认为这可以有效地使用super关键字。 看起来没有办法制作像这样的东西。

(我知道你说S应该是T的子类型,不仅是S的子类型,但我仍然认为这不是必要的。实际上,S可能是任何东西,但是它留下R的子类型允许更多的实现自由。这在这里并不重要。)

有趣的是,可以将其表述为静态方法:

class List<T> {
      /**
       * Creates the intersection of two Lists,
       * adding the resulting elements to another list.
       * @param out the List to which the output should be added.
       *     If null, a new List will be created.
       * @param left the first list to intersect.
       * @param right the second list to intersect
       * @return out, with the intersection of left an right added
       */
    static <R, T extends R, S extends R>
        List<R> intersect(List<R> out, List<T> left, List<S> right) {
        // TODO
        return out;
    }
}

或者,如果您在方法中不需要T和S:

class List<T> {
      /**
       * Creates the intersection of two Lists,
       * adding the resulting elements to another list.
       * @param out the List to which the output should be added.
       *     If null, a new List will be created.
       * @param left the first list to intersect.
       * @param right the second list to intersect
       * @return out, with the intersection of left an right added
       */
    static <R>
        List<R> intersect(List<R> out, List<? extends R> left, List<? extends R> right) {
        // TODO
        return out;
    }
}

当然,当您想要在子类中重写此方法时,这种静态方式不起作用。

答案 2 :(得分:0)

<R> List<R> intersect(List<R> out, List<? extends R> other)
{
    for(R x : other)
        if(this.contains(x))
            out.add(x);
    return out;
}

boolean contains(Object x){ ... }

请注意contains()需要Object,而不是T