为什么不能在Java中创建通用填充方法?

时间:2009-05-04 16:37:22

标签: java generics

我有以下课程:

abstract class DTO{ }

class SubscriptionDTO extends DTO { }

以及以下通用方法:

protected void fillList(ResultSet rs, ArrayList<? extends DTO> l)
        throws BusinessLayerException {
    SubscriptionDTO bs;
    try {
        while (rs.next()){
            //initialize bs object...
            l.add(bs); //compiler error here
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

}

我似乎无法理解为什么你不能创建一个填充DTO子类型的通用方法。我做错了什么还是这个设计?如果是这样,有没有解决方法?提前谢谢。

3 个答案:

答案 0 :(得分:7)

您应该使用<? super DTO>(或<? super SubscriptionDTO>Tom Hawtin - tackline指出)作为ArrayList的通用参数。

Effective Java第28项(sample chapter [pdf]第28页):

  

这是一个助记符,可帮助您记住要使用的通配符类型:

     

PECS代表生产者延伸,消费者超级。

     

换句话说,如果参数化类型代表T生产者,请使用<? extends T>;   如果它代表T个消费者,请使用<? super T>

在这种情况下,l是使用者(您将对象传递给它),因此<? super T>类型是合适的。

答案 1 :(得分:2)

想象一下Foo extends BarZoo extends Bar

以下情况
List<Foo> fooList = new ArrayList<Foo>();
fooList.addAll(aBunchOfFoos());
aMethodForBarLists(fooList);

然后我们有了方法本身:

void aMethodForBarLists (List<? extends Bar> barList) {
   barList.add(new Zoo());
}

这里发生的是,即使Zoo确实扩展了Bar,你也试图在List<Foo>中添加一个动物园,这是为Foos明确制作的。

这个是Java规范不允许在<? extends Something>集合中添加内容的原因 - 它不能确定,虽然语法似乎正确,实际对象允许将内容添加到Collection中。

答案 2 :(得分:2)

这应该有效,而且更直接:

protected void fillList( ResultSet rs, List<DTO> l ) throws BusinessLayerException 
{
   SubscriptionDTO bs;
   try 
   {
      while   ( rs.next() )
      {
         //initialize bs object...
         l.add( bs );
      }
    }
    catch ( SQLException e ) 
    {
       e.printStackTrace();
    }

}