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

Java 将特定于类和特定于方法的泛型封装在一个类型中,java,generics,Java,Generics,假设我需要一个绑定到泛型可比较的类型的类: 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); } } 但发现

假设我需要一个绑定到泛型
可比较的
类型的类:

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);
    }
}
但发现这是不可能的(原因如下)。有没有绕过它的优雅的可能性


编辑:我能想到的一个丑陋的可能性是将封装分成两种不同的类型,并在
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);
    }
}

又好又简单!希望有一天,这将有助于与我处境相同的人。:-)

这能解决问题吗

class A<V, T extends MyT<T, V>> {

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

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

    public <V> Future<V> submit(MyT<T, V> task) {
        return ...;
    }
}

class MyT<T, V> implements Comparable<T>, Callable<V> {

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

    @Override
    public V call()
        throws Exception {

        return ...;
    }
}
A类{
//这只是T类型用法的一个示例
列出可比数据;
整数比较法(T smth){
返回可比数据。获取(0)。比较到(smth);
}
公共未来提交(MyT任务){
返回。。。;
}
}
类MyT实现了可比较的、可调用的{
@凌驾
公共内部比较(TO){
返回0;
}
@凌驾
公共电话
抛出异常{
返回。。。;
}
}

类似的方法可能会奏效:

class A<T extends Comparable<T>> {
    List<T> comparables;

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

    public Future<T> submit(B<T> task) {
        return someExecutorService.submit(task);
    }

    public class B<T> implements Callable<T> {
        ...
    }  
}
A类{
列出可比数据;
整数比较法(T smth){
返回可比数据。获取(0)。比较到(smth);
}
公共未来提交(B任务){
返回服务。提交(任务);
}
公共类B实现了可调用{
...
}  
}
好的,真的是最后一次尝试。 能否将泛型函数更改为泛型嵌套类或内部类?像这样:

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);
    }

    class B<V> 
     {
      T t;
      T getT() { return t; }
      Callable <V> v;
      Callable <V> getV() { return v; }
      public Future<V> submit(B<V> task) {
           if(compareSomething(task.getT()) != 0)
            throw new RuntimeException("");
        return SomeExecutorService.submit(task.getV());
    }
}
A类{
//这只是T类型用法的一个示例
列出可比数据;
整数比较法(T smth){
返回可比数据。获取(0)。比较到(smth);
}
B类
{
T;
T getT(){return T;}
可调用v;
可调用的getV(){return v;}
公共未来提交(B任务){
if(比较方法(task.getT())!=0)
抛出新的RuntimeException(“”);
返回SomeExecutorService.submit(task.getV());
}
}

我不知道如何在
Callable
方法参数中同时结合你的泛型类参数
t
V
,原因在链接帖子的答案中列出。但是,也许这是一个选项——我无法估计改变submitt的行为会有多违反直觉将一个任务绑定到一个在任务本身上被调用的方法?类似于

class A<T extends Comparable<T> & Callable<?>> {

    public static abstract class Submittable<T extends Submittable<T,V>,V>
      implements Comparable<T>, Callable<V> {
        // ugly, but unavoidable
        @SuppressWarnings("unchecked")
        public Future<V> submitTo(A<? super T> scheduler) {
          return (Future<V>) scheduler.submit((T) this);
        }
    }

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

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

    // *can* be left public, but that way you enforce a single way
    // of submitting tasks, namely via submitTo
    private Future<?> submit(T task) {
        if(compareSomething(task) != 0)
            throw new RuntimeException("");
        // the following cast is a save conversion - you could also write it cast-free
        // as Callable<?> callable = task; ...submit(callable);
        return someExecutorService.submit((Callable<?>) task);
    }
}
A类提交(T任务){
如果(比较方法(任务)!=0)
抛出新的RuntimeException(“”);
//下面的强制转换是一个保存转换-您也可以将其写入强制转换
//as Callable Callable=task;…submit(可调用);
返回someExecutorService.submit((可调用)任务);
}
}
现在,您的所有任务都必须继承
A.Submittable
,然后可以通过
submitTo
提交到调度程序实例,返回正确类型
V
Future


当然,这主要依赖于
T
实际上是
Submittable
子类的一个自类型。而
submitTo
中发生的事情——嗯,很难看。但它确实为您提供了返回正确类型的
未来
的便利。

使用
可比
来约束参数,而不仅仅是
T

如果唯一的条件是对象是
可调用的
可比较的
,那么您可以将这两个接口放在参数上。如果需要添加命名类来满足另一个需求,那么它甚至保留了向参数添加命名类的选项。您需要抑制一个警告,但这是一个安全的抑制,因为您知道
T
扩展了
Comparable

公共A类{
//这只是T类型用法的一个示例
列出可比数据;
ExecutorService someExecutorService=null;
整数比较法(T smth){
返回此.compariables.get(0).comparieto(smth);
}
未来提交(可调用任务){
返回此.someExecutorService.submit(任务);
}
@抑制警告(“未选中”)
未来更好提交(W任务){
如果(此比较方法((T)任务)!=0)
抛出新的RuntimeException(“”);
返回此.someExecutorService.submit(任务);
}
}

我在另一个类中遇到了同样的问题,它引用自身作为自己的泛型参数,如下所示。我不认为这是一个干净的实现,但我喜欢你的例子。它提供了一个很好的整洁的用例,我可以在之后对一些新代码进行模式化。我通常不喜欢抑制警告,但我并不介意,因为只有这种方法会受到影响。我希望这会有帮助

为什么像这样简单的事情不行

public class CustomThreadPool {
    public <CallableReturn> Future<CallableReturn> submit(SelfSchedulingCallable<CallableReturn> task) {
        // Use comparePriority or any other interface methods needed to determine scheduling
    }
}

public interface SelfSchedulingCallable<V> extends Callable<V> {
    public boolean isBlockedBy(SelfSchedulingCallable<?> otherTask); // Doesn't care about the return type of otherTask
    public boolean invokeAfter(SelfSchedulingCallable<?> otherTask);
    public int comparePriority(SelfSchedulingCallable<?> otherTask);
}
公共类CustomThreadPool{
公共未来提交(自调度可调用任务){
//使用comparePriority或确定调度所需的任何其他接口方法
}
}
公共接口SelfSchedulingCallable扩展了Callable{
public boolean isBlockedBy(SelfSchedulingCallable otherTask);//不关心otherTask的返回类型
公共布尔invokeAfter(SelfSchedulingCallable otherTask);
公共内部比较优先级(自调度可调用的其他任务);
}
我认为埃里克·罗伯逊的方案最接近直接解决方案。我想提出一个不太直接的方法(避免任何未经检查的强制转换)。你写道:

此服务只接受一种特殊类型的
可调用任务。那些
可调用的
必须实现一个与
可比较的
接口类似的自定义接口

如果我们真的声明了您描述的类型,我们会得到这个交集接口:

interface CustomCallable<V> extends Callable<V>, Comparable<CustomCallable<?>> { }
interface CustomCallable<V, SELF> extends Callable<V>, Comparable<CustomCallable<?, ?>> { }
如果您坚持对特定类型的自定义可调用函数参数化
A
,则会变得更加复杂。唯一可行的方法是向intersecti添加一个“自我类型”参数
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);
    }
}
public class CustomThreadPool {
    public <CallableReturn> Future<CallableReturn> submit(SelfSchedulingCallable<CallableReturn> task) {
        // Use comparePriority or any other interface methods needed to determine scheduling
    }
}

public interface SelfSchedulingCallable<V> extends Callable<V> {
    public boolean isBlockedBy(SelfSchedulingCallable<?> otherTask); // Doesn't care about the return type of otherTask
    public boolean invokeAfter(SelfSchedulingCallable<?> otherTask);
    public int comparePriority(SelfSchedulingCallable<?> otherTask);
}
interface CustomCallable<V> extends Callable<V>, Comparable<CustomCallable<?>> { }
class A {

    List<CustomCallable<?>> customCallables;

    int compareSomething(CustomCallable<?> smth) {
        return customCallables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(CustomCallable<V> task) {
        if (compareSomething(task) != 0) {
            throw new RuntimeException("");
        }
        return someExecutorService.submit(task);
    }
}
interface CustomCallable<V, SELF> extends Callable<V>, Comparable<CustomCallable<?, ?>> { }
class A<T extends CustomCallable<?, ?>> {

    List<CustomCallable<?, T>> customCallables;

    int compareSomething(CustomCallable<?, T> smth) {
        return customCallables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(CustomCallable<V, T> task) {
        if (compareSomething(task) != 0) {
            throw new RuntimeException("");
        }
        return someExecutorService.submit(task);
    }
}
class MyCustomCallable<V> implements CustomCallable<V, MyCustomCallable<?>> {
    ...
}
A<MyCustomCallable<?>> pool = new A<>();

MyCustomCallable<String> strCallable = ...;
MyCustomCallable<Integer> intCallable = ...;

Future<String> strFuture = pool.submit(strCallable);
Future<Integer> intFuture = pool.submit(intCallable);