通用类和方法

时间:2011-12-12 16:33:05

标签: java generics pagination playframework

我正在为我的java项目开发一个分页系统,我想让它适用于我的各种JPA模型。

问题(据我所知)是,如果我使用泛型,我将不得不以某种方式投射返回的最终值来处理它。我怎么能避免这种情况?

到目前为止,这是我的代码(绝对不是通用的!):

public interface Paginator {
    public void setLimit(Integer limit);
    public Page page(Integer page);
}


public class PicturesPaginator implements Paginator {
    private Integer limit = 10;
    private JPAQuery query;
    private Long quantity;

    public PicturesPaginator(String query, Object... params) {
        this.query = Picture.find(query, params);
        this.quantity = Picture.count(query, params);
    }

    @Override
    public void setLimit(Integer limit) {
        this.limit = limit;
    }

    @Override
    public PicturesPage page(Integer page) {
        if (page == null)
            page = 1;

        List<Picture> pictures = query.fetch(page, limit);
        return new PicturesPage(pictures, quantity, page, limit);
    }
}


public abstract class Page {
    protected List<Picture> pictures;
    protected Long quantity;
    protected Integer page;
    protected Integer limit;

    public List<Picture> list() {
        return pictures;
    }

    public Long count() {
        return quantity;
    }

    public boolean hasNext() {
        return (page * limit > quantity);
    }

    public boolean hasPrevious() {
        return (page != 1);
    }

    public boolean hasOtherPages() {
        return (hasNext() || hasPrevious());
    }

    public Integer nextPageNumber() {
        if (!hasNext())
            return null;

        return (page + 1);
    }

    public Integer previousPageNumber() {
        if (!hasPrevious())
            return null;

        return (page - 1);
    }

    public Integer currentPageNumber() {
        return page;
    }
}


public class PicturesPage extends Page {
    public PicturesPage(List<Picture> pictures, Long quantity, Integer page, Integer limit) {
        this.pictures = pictures;
        this.quantity = quantity;
        this.page = page;
        this.limit = limit;
    }
}

我想摆脱那些PicturesPaginatorPicturesPage并使其成为通用的,但抽象类Page中的list()方法将返回一个通用列表({{1} }或List<T>因为我在这里使用Play)。 我期望的是这个List<GenericModel>方法返回正确的List,在我的情况下又称list()。这可能吗?

注意:我现在在Play中有一个分页模块!框架,我的问题主要是为了更多地了解java :))

非常感谢你的帮助,我真的很感激!

5 个答案:

答案 0 :(得分:3)

您可以查看我的Play - Pagination模块的源代码,看看我是如何处理这类事情的。我把source on github

你想要做的是使页面也是通用的,也可能是非抽象的:

public class Page<T> {
  public List<T> list() {}
}

而不是PicturePage,你可以这样做:

new Page<Picture>()

Paginator界面也需要通用化:

public interface Paginator {
    public Page<T> page(Integer page);
}

由于您在Picture类上调用方法,因此Generifying PicturesPaginator会更难。 Java的泛型实现在运行时擦除类型,因此您必须处理类型标记和反射。

public abstract class GenericPaginator<T> {
  public GenericPaginator() {
    Class<T> typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    // use reflection to invoke the finders methods
  }
}
public class PicturesPaginator extends GenericPaginator<Picture> {}

答案 1 :(得分:1)

  

我期望这个list()方法返回正确的List,   在我的案例中也称列表。这可能吗?

这不仅仅是可能的,如果您正确使用泛型,那就是您自动获得的。如果你宣布

public class Page<T extends GenericModel>{
    protected List<T> items;

    public List<T> list() {
        return items;
    }
}

并像这样使用它:

page = new Page<Picture>();

然后page.list()实际上将返回List<Picture>,因为T是一个类型参数,当Page时由具体类型替换声明了。

答案 2 :(得分:1)

如果我理解正确,以下内容可能有所帮助:

让Pace变得通用。转

public abstract class Page {
    protected List<Picture> pictures;

    public List<Picture> list() {
        return pictures;
    }

为:

public abstract class Page<Element> {
    protected List<Element> elements;

    public List<Element> list() {
        return elements;
    }

比使图片页面更加具体:

public class PicturesPage extends Page<Picture> {

答案 3 :(得分:1)

我不确定这是否是您所需要的,但您可以将Page类转换为:

public abstract class Page<T> {
    protected List<T> pictures;
    protected Long quantity;
    protected Integer page;
    protected Integer limit;

    public List<T> list() {
        return pictures;
    }

    public Long count() {
        return quantity;
    }

    public boolean hasNext() {
        return (page * limit > quantity);
    }

    public boolean hasPrevious() {
        return (page != 1);
    }

    public boolean hasOtherPages() {
        return (hasNext() || hasPrevious());
    }

    public Integer nextPageNumber() {
        if (!hasNext())
            return null;

        return (page + 1);
    }

    public Integer previousPageNumber() {
        if (!hasPrevious())
            return null;

        return (page - 1);
    }

    public Integer currentPageNumber() {
        return page;
    }

答案 4 :(得分:1)

如果我理解正确,那么在这里引入泛型的问题就是这样的行:

this.query = Picture.find(query, params);

AFAIK你不能直接在泛型类型上调用静态方法,所以你必须在这里使用反射。在这种情况下,您可能必须将参数类型的类作为参数传递(或者从反射数据中获取它(如果存在)),找到要调用的方法并调用它。

这是这样的:

 Class<T> clazz;

 public Paginator (Class<T> clazz) {
    this.clazz = clazz;

    //note that you need to handle exceptions, I'll leave them out for brevity
    Method findMethod = clazz.getMethod("find", String.class, Array.class ); 
    this.query = findMethod.invoke(null, query, params);
 }

修改

作为替代方案,将“finder”对象传递给通用Paginator,并使其实现提供find(...)count(...)方法的接口:

interface Finder<T> {
  JPAQuery find( String query, Object... params);
  Long count( String query, Object... params);
} 

class Paginator<T, F extends Finder<T>> {
  public Paginator(F finder, String query, Object... params) {
    this.query = finder.find(query, params);
    ...
  }

  ...
}