使用参数指定有效的泛型类型

时间:2013-07-15 11:47:42

标签: java generics

考虑以下课程

public interface SortBy<S> {
}

public class CommentSortBy<S> implements SortBy<S> {
    public static CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
    public static CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}

public class SomeQueryUnsafe {
    public <M, S extends SortBy<M>> void setSort(S sortBy, M min) {
        //Set relevant values
    }
}

目前用作:

public SomeQueryUnsafe createCommentQueryUnsafe() {
    return new SomeQueryUnsafe();
}

public void test() {
    createCommentQueryUnsafe().setSort(CommentSortBy.CREATION, new Date());
}

虽然这有效,但问题是createCommentQueryUnsafe()未指定sortBy的限制。用户可以自由地传递UserSortBy.NAME,即使在这种情况下没有意义

我无法弄清楚如何写这个,因为只是将<B extends SortBy>添加到类签名意味着我失去了限制方法中min参数的能力。我不能使用<M, S extends B & SortBy<M>>之类的内容作为its a compiler error。使用通配符魔法的其他尝试只会导致更高的复杂性和编译器错误。将排序移动到createCommentQuery()方法意味着每个查询都需要2个方法,这是一个疯狂的重复代码量

我如何编写泛型,以便createCommentQuery()sortBy参数限制为CommentSortBy,同时仍然将min限制在SortBy类中的S参数?< / p>

1 个答案:

答案 0 :(得分:3)

出于你所指出的原因,这确实是一个棘手的问题。我尝试了各种方法,但它们都被generics limitation you cited击败了。最终,如果您想要指定的类型安全,您似乎需要进行一些设计更改。

对于通用类型限制使用SortBy实现的继承层次结构似乎特别导致了这种僵局。我尝试将该限制解耦为SortBy上的新类型参数,该参数代表查询对象本身,例如CommentUser等。这是我提出的设计:

static class Comment { }

static class User { }

interface SortBy<T, M> { }

static class CommentSortBy<M> implements SortBy<Comment, M> {

    static final CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
    static final CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}

static class UserSortBy<M> implements SortBy<User, M> {

    static final UserSortBy<String> NAME = new UserSortBy<String>();
}

static class Query<T> {

    public <M> void setSort(SortBy<T, M> sortBy, M min) {
        //Set relevant values
    }
}

public static void main(String[] args) {

    new Query<Comment>().setSort(CommentSortBy.CREATION, new Date());
    new Query<Comment>().setSort(UserSortBy.NAME, "Joe"); //compiler error
}

ideone