Java循环泛型

时间:2009-08-10 08:43:54

标签: java generics

我在理解Java泛型方面遇到了问题,我已经简化为这个例子

class A<T extends B> {

    public void fun(T t) {

    }
}

class B {
    A a;

    public void event() {
        a.fun(this);
    }

}

问题是这会产生警告,因为A在B中定义但A已经将其用作泛型类型。

我的第一直觉是我的设计错了,但在这种情况下我无法改变它。 A就像一个集合,B就像集合中的一个节点,用户应该覆盖它。某些事件可能发生在B中,需要向父母A报告。

但由于A一般用B定义,我如何避免B.event()中的编译警告

由于

2 个答案:

答案 0 :(得分:13)

问题是你在这一行上使用的是原始类型:

A a;

您需要为A的类型参数(T)指定类型。

你可以这样做:

A<B> a;

但是如果我理解你对这个问题的陈述,那么A根本不是通用的。你可能想做这样的事情:

class A<T> {
  public void fun(T t) {

  }
}

class B<T extends B<T>> {
  A<B<T>> a;
  public void event() {
    a.fun(this);
  }
}    

甚至是这样:

class A<T extends B<? extends T>> {
  public void fun(T t) {

  }
}

class B<T extends B<T>> {
  A<? super B<T>> a;
  public void event() {
    a.fun(this);
  }
}

这些之间存在一些可能有用的变化。后一个例子是最通用的(但显然也是最复杂的)。

class A<T extends B<? extends T>>确保A的类型参数是B.因为B本身是通用的,并且具有该循环类型参数,所以最终需要说B<? extends T>(简单地说T赢了)在这里工作。

class B<T extends B<T>>尽可能接近在Java中模拟“自我类型”。这让B谈论自己的(几乎)具体的子类型。当继承B时,你会说“class C extends <B<C>>”之类的东西。这很有用,因为现在C.a的类型实际上是A<? super B<C>>

后一个示例中的? super位仅在您计划将B与A连接时才有用,该B不是完全相同类型的A<Shape>。用具体的方式思考,假设你有一个Circle和一个Shape(扩展B扩展A<Circle>)。超级通配符允许您一起使用它们。没有它,您需要A<Shape>而不是Circle {{1}}。

答案 1 :(得分:11)

<强>代码

public class A<T extends B> {
    public void fun(T t) {
    }
}

public class B {
    A<B> a;

    public void event() {
        a.fun(this);
    }
}

警告被征服了。

<强>原因

类型A的变量应使用特定的类类型声明,如泛型类签名(A<T extends B>)所示。< / p>

解决

虽然这解决了编译器警告,但仍存在潜在问题。劳伦斯为核心问题提供了出色的解释和解决方案。