将类特定和特定于方法的泛型封装在一种类型中

hoe*_*ing 14 java generics

假设我需要一个与泛型Comparable类型相关的类:

class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }
}
Run Code Online (Sandbox Code Playgroud)

该类具有签名中具有自己的泛型的方法:

<V> Future<V> submit(Callable<V> task) {
    return someExecutorService.submit(task);
}
Run Code Online (Sandbox Code Playgroud)

现在,是否有可能限制submit方法的输入只接受Callables也实现T?我第一次尝试这个:

<V, W extends T & Callable<V>> Future<V> submit(W task) {
    if(compareSomething(task) != 0)
        throw new RuntimeException("");
    return someExecutorService.submit(task);
}
Run Code Online (Sandbox Code Playgroud)

但发现它是不可能的(由于此处所述的原因).有没有优雅的可能性绕过它?


编辑:我能想到的一个丑陋的可能性是将封装分成两种不同的类型并传递一个对象submit:

class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }
    <V> Future<V> submit(Callable<V> task, T comparable) {
        if(compareSomething(comparable) != 0)
            throw new RuntimeException("");
        return someExecutorService.submit(task);
    }
}
Run Code Online (Sandbox Code Playgroud)

主要的缺点是方法签名变得更加复杂,对于后面的代码,我还需要Ts与Callables 的一对一映射.也许人们可以建议一种以适当的方式解决它的模式?


编辑,采取两个:让我简要解释一下我想要实现的目标.我正在开发一个能够执行某种特殊任务调度的自定义线程池实现.为此,此服务仅接受一种特殊Callable任务.那些Callable必须实现类似于那个的自定义接口Comparable.通过使用此接口中的方法比较任务对,服务将:

  1. 如果传入任务被任何正在运行的任务阻止,则阻止该任务.
  2. 完成任务后调用挂起的任务Future.
  3. 通过比较确定待处理任务的执行顺序.

阻塞/比较逻辑应由任务本身提供.这样,线程池类应该只定义Comparable池对象接受的特殊类型,并且它根本不关心Callable它们实际是什么类型以及它们的返回类型是什么.


编辑,取三:根据Erick Robertson回答,现在可以防止提交臭臭任务:

public static void test(String[] args) {
    A<Valid> scheduler = new A<>();
    scheduler.betterSubmit(new Valid()); // applies to method signature
    scheduler.betterSubmit(new Forbidden()); // rejected on compile time
    scheduler.betterSubmit(new ConformWithValid()); // still appliable because all required interfaces implementations recognised
}

// just a bunch of test classes

private static class Valid implements Comparable<Valid>, Callable<Void> {

    @Override
    public int compareTo(Valid o) {
        return 0;
    }

    @Override
    public Void call() throws Exception {
        return null;
    }
}

private static class Forbidden implements Comparable<Forbidden>, Callable<Void> {

    @Override
    public int compareTo(Forbidden o) {
        return -1;
    }

    @Override
    public Void call() throws Exception {
        return null;
    }
}

private static class ConformWithValid implements Comparable<Valid>, Callable<Boolean> {

    @Override
    public int compareTo(Valid o) {
        return 1;
    }

    @Override
    public Boolean call() throws Exception {
        return Boolean.FALSE;
    }
}
Run Code Online (Sandbox Code Playgroud)

好,易于!希望有一天,这将有助于与我的情况相同的人.:-)

Eri*_*son 3

用于Comparable<T>约束参数而不仅仅是T

如果唯一的标准是对象是CallableComparable,那么您可以将这两个接口放在参数上。如果需要满足另一个要求,甚至保留向参数添加命名类的选项。您需要抑制一个警告,但这是一种安全的抑制,因为您知道它T会扩展Comparable<T>.

public class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    ExecutorService someExecutorService = null;

    int compareSomething(T smth) {
        return this.comparables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(Callable<V> task) {
        return this.someExecutorService.submit(task);
    }

    @SuppressWarnings("unchecked")
    <V, W extends Callable<V> & Comparable<T>> Future<V> betterSubmit(W task) {
        if(this.compareSomething((T) task) != 0)
            throw new RuntimeException("");
        return this.someExecutorService.submit(task);
    }
}
Run Code Online (Sandbox Code Playgroud)

我在另一个类中遇到了同样的问题,该类将自身引用为自己的通用参数,如下所示。我认为这还不是一个干净的实现,但我喜欢你的例子。它提供了一个很好的简洁用例,我可以根据它来设计一些新代码。我通常不喜欢抑制警告,但我并不介意,因为只有这个方法受到影响。我希望这个能帮上忙!