假设我使用的界面与通用类型参数

interface Foo<T> {
  T getOne();
  void useOne(T t);
}

的目的是,类型T是抽象的。它强制上Foo的实现类型约束,但是客户端代码不完全关心T是什么

这是在一般方法的上下文中没有问题:

public <T> void doStuff(Foo<T> foo) {
  T t = foo.getOne();
  /* do stuff */
  foo.useOne(t);
}

但是假设我要分手doStuff的工作,节省了一类Bar一些状态。在这种情况下,我似乎需要Foo的类型参数添加到Bar

public class Bar<T> {
  private Foo<T> foo;
  private T t;

  /* ... */

  public void startStuff() {
    t = foo.getOne();
  }

  public void finishStuff() {
    foo.useOne(t);
  }
}

这是一种奇怪的,因为类型参数TBar的公共接口出现(即,它不包含在任何方法参数或返回类型)。有没有一种方法,以“量化T走”?即,我可以安排参数TBar的接口被隐藏,如以下

public class Bar {
  <T> { // foo and t have to use the same T
    private Foo<T> foo;
    private T t;
  } // T is out of scope
  ... 
}
有帮助吗?

解决方案

您的问题是类似于由一个“捕获解决帮手”,但我不知道在哪里使用两种不同的方法可以应用到你的第二个例子。你的第一个doStuff方法绝对可以更好地写成public void doStuff(Foo<?> foo),因为它的工作原理,无论Foo类型的参数。然后,“捕获辅助”模式将是有用的。


更新:摆弄了一下,延长戈茨的捕捉帮手的想法后,我想出了这个。在内部,它看起来有点凌乱;从外面看,你不会怀疑的事情。

public class Bar {
  private final Helper<?> helper;
  public Bar(Foo<?> foo) {
    this.helper = Helper.create(foo);
  }
  public void startStuff() {
    helper.startStuff();
  }
  public void finishStuff() {
    helper.finishStuff();
  }
  private static class Helper<T> {
    private final Foo<T> foo;
    private T t;
    private Helper(Foo<T> foo) {
      this.foo = foo;
    }
    static <T> Helper<T> create(Foo<T> foo) {
      return new Helper<T>(foo);
    }
    void startStuff() {
      t = foo.getOne();
    }
    void finishStuff() {
      foo.useOne(t);
    }
  }
}

其他提示

要是有用的,在某些时候你要设置foo字段。在这一点上,你应该知道(或能够捕捉)T。我建议这样做,在构造函数中,然后它将使意义Bar有一个泛型参数。你甚至可以使用一个接口,这样客户端代码没有看到类型。不过,我想你不会把我的建议,真的想要一个setFoo。所以只加一个点,可切换的实现:

/* pp */ class final BarImpl<T> {
    private final Foo<T> foo;
    private T t;

    BarImpl(Foo<T> foo) {
        this.foo = foo;
    }

    public void startStuff() {
        t = foo.getOne();
    }

    public void finishStuff() {
        foo.useOne(t);
    }
}

public final class Bar {
    private BarImpl<?> impl;

    /* ... */

    // Need to capture this wildcard, because constructors suck (pre-JDK7?).
    public void setFoo(Foo<?> foo) {
        setFooImpl(foo);
    }
    private <T> void setFooImpl(Foo<T> foo) {
        impl = new BarImpl<T>(foo);
    }

    public void startStuff() {
        impl.startStuff();
    }

    public void finishStuff() {
        impl.finishStuff();
    }
}

为什么不具有三层的层次结构:

abstract class Foo

abstract class FooImplBase<T> extends Foo

class Bar extends FooImplBase<String>

客户端只知道Foo,其中不包含任何通用的方法。介绍你FooImplBase<T>需要任何通用的方法,然后具体类提炼出来的。

因此,在你的榜样startStuff()endStuff()将是Foo抽象和FooImplBase<T>实施。这听起来像它可能在你的真实情况下工作?我同意它有点麻烦的。

您正在定义的酒吧类。有两两件事是真的......

1)是一种参与酒吧没有参数类型。也就是说,foo和t个成员具有单一类型,说U,其被固定为定义。如果你通过了,你希望分配给FOO一个Foo,它必须是一个Foo 。如果这都是真的,那么,它不是公共接口的一部分 - 任何事物都有一个特定的类型。然后,我不知道你所说的“量化”的意思,因为世上没有免费的类型变量。如果你的意思是普遍量化,你如何调和这条没有任何参数打字的事实,因此必须被赋予了具体的类型,每次的成员?

2)是一种参与酒吧的参数的类型。它可能不是很明显的公共接口,但也许你在一个Foo 通过,所以你想有一个酒吧类具有比单一类型更被实例化。然后,如前所述,这是在公共接口,而你需要做律师参数T中使用泛型。这给了你某种形式的定义普遍量化的,“对于所有类型的T,这个定义是真实的。”

某处它必须决定了,你要使用的“T”的酒吧类的内部是什么类型。所以,要么你必须选择它吧(更换美孚由富的类定义中),或者你把它留给酒吧类的客户端的定义:在这种情况下,酒吧必须由通用

如果你想有一个接口来酒吧不依赖于T的的能够选择不同类型的T,你应该使用非泛型接口或抽象基类,如:

interface Bar {
  void startStuff();
  // ...
}

class BarImplement<T> {
  private Foo<T> foo;
  // ...
}

如果你真的想画一些愤怒,你可以把酒吧类美孚界面里面,吸的这种方式,吨。请参见这篇文章有关内部接口的类的更多信息。也许这是一种情况是有意义

interface Foo<T> {
  T getOne();
  void useOne(T t);

  public class Bar<T> {
    private Foo<T> foo;
    private T t;
    public void startStuff() {
      t = foo.getOne();
    }
    public void finishStuff() {
      foo.useOne(t);
    }
  }
}

在这种情况下的参数T变得无用尽可能酒吧而言,因为其将被擦除在编译时对象。所以,你可以和“不要自找麻烦”,并执行擦除早:

public class Bar {

    private Foo<Object> foo;
    private Object t;

  ... 
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top