T 扩展了 Comparable

发布于 2024-12-12 00:45:59 字数 665 浏览 0 评论 0原文

我有以下课程。

class MyClass<T>

它使用以下构造函数。

MyClass(Comparator<T> comparator, Collection<? extends T> data)

它有一个在构造函数中设置的字段,如下所示:

this.data = Collections.unmodifiableCollection(data);

在 T 实现 Comparable 的特殊情况下,我不想要求传入比较器,因为我可以只使用自然排序。所以我想我应该能够使用这个构造函数:

public <T extends Comparable<T>> MyClass(Collection<T> data)

但显然存在类型不匹配:无法从 Collection转换;收藏 。我尝试过各种方法:添加更多通用参数等等,但都不起作用。我似乎无法指定一个界限:如果您有一个实现 Comparable 的类型 T,请执行简单的操作。

有什么想法吗?

谢谢。

I have the following class.

class MyClass<T>

It uses the following constructor.

MyClass(Comparator<T> comparator, Collection<? extends T> data)

And it has a field which is set in the constructor like so:

this.data = Collections.unmodifiableCollection(data);

In the special case where T implements Comparable, I don't want to require that a comparator be passed in, since I can just use the natural ordering. So I thought I should be able to use this constructor:

public <T extends Comparable<T>> MyClass(Collection<T> data)

But there is apparently a type mismatch: cannot convert from Collection<T> to Collection<? extends T> in the assignment statement above. I've tried all sorts of things: adding more generic parameters, and so on, but none work. I seem unable to specify a bound that says: if you have a type T that implements Comparable, do the straightforward thing.

Any ideas?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一张白纸 2024-12-19 00:45:59

不幸的是,我认为这种“if Comparable do this else do that”的逻辑在 Java 类型系统中是不可能的。

您可以将可比较和不可比较的情况拆分为单独的类并将它们隐藏在接口后面,如下所示:

interface Interface<T> {
    public void processData();
}

class MyClass<T> implements Interface<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class MyCompClass<T extends Comparable<T>> implements Interface<T> {
    private final Collection<? extends T> data;
    MyCompClass(Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> Interface<T> create(Collection<? extends T> data) {
        return new MyCompClass<T>(data);
    }
    static <T> Interface<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}

但这可能会导致大量重复的代码。另一种选择是让 MyClass 在其构造函数中需要 Comparator,并在工厂中构建该比较器:

class MyClass<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> MyClass<T> create(Collection<? extends T> data) {
        return new MyClass<T>(new Comparator<T>() {
            public int compare(T o1, T o2) {
                return o1.compareTo(o2);
            }
        }, data);
    }
    static <T> MyClass<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}

Unfortunately I don't think this kind of "if Comparable do this else do that" logic is possible with the Java type system.

You could split the Comparable and non-Comparable cases into separate classes and hide them behind an interface, something like this:

interface Interface<T> {
    public void processData();
}

class MyClass<T> implements Interface<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class MyCompClass<T extends Comparable<T>> implements Interface<T> {
    private final Collection<? extends T> data;
    MyCompClass(Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> Interface<T> create(Collection<? extends T> data) {
        return new MyCompClass<T>(data);
    }
    static <T> Interface<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}

But this might result in a lot of duplicated code. Another option is to leave MyClass requiring a Comparator in its constructor, and build that comparator in the factory:

class MyClass<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> MyClass<T> create(Collection<? extends T> data) {
        return new MyClass<T>(new Comparator<T>() {
            public int compare(T o1, T o2) {
                return o1.compareTo(o2);
            }
        }, data);
    }
    static <T> MyClass<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}
罪#恶を代价 2024-12-19 00:45:59

我同意这似乎是不可能的,因为

class MyClass<T> {

    Collection<? extends T> data;

    public MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }

    public <E extends T & Comparable<T>> MyClass(Collection<E> data) {
        this.data = data;
    }

}

编译器拒绝了

直接的解决方案

当第一个绑定是类型参数时,无法指定任何其他绑定Comparable

另请参阅 为什么我不能在具有多个边界的类型参数中使用类型实参?(特别是 Chris波维克的回答)。

至于解决方案,我同意 Chris B.

I concur this appears to be impossible, as the straightforward solution

class MyClass<T> {

    Collection<? extends T> data;

    public MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }

    public <E extends T & Comparable<T>> MyClass(Collection<E> data) {
        this.data = data;
    }

}

is rejected by the compiler with

Cannot specify any additional bound Comparable<T> when first bound is a type parameter

See also Why can't I use a type argument in a type parameter with multiple bounds? (in particular Chris Povirk's answer).

As for solutions, I agree with Chris B.

旧街凉风 2024-12-19 00:45:59

您可以对第一种情况使用常规构造函数,对第二种情况使用工厂方法:

class MyClass<T> {

    Collection<? extends T> data;
    Comparator<? super T> comparator;

    public MyClass(Comparator<? super T> comparator, Collection<? extends T> data) {
        this.data = data;
        this.comparator = comparator;
    }

    public static <T extends Comparable<? super T>> MyClass<T> fromComparable(Collection<T> data) {
        return new MyClass<T>(Collections.reverseOrder(Collections.reverseOrder()), data);
    }

}

You can use the regular constructor for the first case and a factory method for the second one:

class MyClass<T> {

    Collection<? extends T> data;
    Comparator<? super T> comparator;

    public MyClass(Comparator<? super T> comparator, Collection<? extends T> data) {
        this.data = data;
        this.comparator = comparator;
    }

    public static <T extends Comparable<? super T>> MyClass<T> fromComparable(Collection<T> data) {
        return new MyClass<T>(Collections.reverseOrder(Collections.reverseOrder()), data);
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文