我正在尝试使用适配器模式构建SDK。到目前为止,这是我得到的:

interface Adapter<T> {
  void doWork(WorkUnit<T> unit);
  Class<T> getT();
}

class WorkUnit<T> {
  public int getId() { ... }
  public T getExtras() { ... }
}

class OldWorkUnit {
  public <T> void setExtra(T data) { /* Store data in Map<Class, Object> */ }
  public <T> WorkUnit<T> toNewWorkUnit(Adapter<T> adapter) { /* Map.get(adapter.getT()) */ }
}


那里有很多泛型,但是我在编译时不知道T,并且可能有多个Adapter,它们都具有不同的T类型。这意味着要暴露给第三方,因此我也需要很少的接口实现中的实现,并且它必须是接口(没有抽象类)。

现在,我要接受这个,并使用WorkUnit调用doWork。我的第一遍代码如下所示:

class FooAdapter implements Adapter<FooWorkUnit> {
  ...
}

OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);

a.doWork(unit);


嗯,那不会编译:

The method doWork(WorkUnit<capture#2-of ?>) in the type Adapter<capture#2-of ?>
is not applicable for the arguments (WorkUnit<capture#4-of ?>)


我知道WorkUnit泛型参数与Adapter.doWork()泛型参数具有相同的类型,但是在不知道类型的情况下,我无法对其进行适当的转换。

那么有什么办法可以解决这个问题吗?

最佳答案

您为何在此处对模板类进行通配?:

Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);


如果您这样做:

Adapter<FooWorkUnit> a = new FooAdapter();
WorkUnit<FooWorkUnit> unit = w.toNewWorkUnit(a);


这样不能保留您的需求吗?

现在,编译器知道FooWorkUnit是公分母。

编辑:关于运行时可变性的确定点。如何强行键入有效的方法,以便消除通配符,但仍保持一致:

@SuppressWarnings("unchecked")
public <X> void prepareArgsAndDoTheWork() {
    OldWorkUnit w = new OldWorkUnit();
    w.setExtra(new FooWorkUnit());

    Adapter<X> a = (Adapter<X>) ... ; // Obtain the Adapter by reflection etc
    WorkUnit<X> unit = w.toNewWorkUnit(a);
    a.doWork(unit);
}

关于java - 尝试在Java中构建可扩展的数据对象和适配器模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8088286/

10-09 18:39