题
假设我使用的界面与通用类型参数
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);
}
}
这是一种奇怪的,因为类型参数T
不Bar
的公共接口出现(即,它不包含在任何方法参数或返回类型)。有没有一种方法,以“量化T
走”?即,我可以安排参数T
在Bar
的接口被隐藏,如以下
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,你应该使用非泛型接口或抽象基类,如:
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;
...
}