2009-08-10 68 views
5

我在理解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.

发生但是由于是为B一般定义,如何避免内部B.event()编译警告

感谢

+0

我能看到的唯一警告是使用A作为原始类型。如果这不是你所指的警告,请更具体,并告诉我们您正在使用的编译器。 – skaffman 2009-08-10 08:52:52

回答

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>)所建议的。

分辨率

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

13

问题是,你正在使用这条线原始类型:

A a; 

你需要指定一个的类型参数(T)类型。

你可以做这样的事情:

A<B> 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连接起来,而该A不是与B完全相同的类型。具体思考,假设您有A<Shape>Circle(其延伸Shape,其延伸B)。超级通配符可让您一起使用它们。没有它,你需要一个A<Circle>而不是A<Shape>你的Circle

+0

这是正确的,和通配符的一个很好的例子。 – 2009-08-10 15:50:03