Chr*_*way 9 java generics adts
假设我使用的是具有泛型类型参数的接口
interface Foo<T> {
T getOne();
void useOne(T t);
}
Run Code Online (Sandbox Code Playgroud)
意图是类型T
是抽象的:它对实现强制执行类型约束Foo
,但客户端代码并不关心究竟是什么T
.
这在通用方法的上下文中没有问题:
public <T> void doStuff(Foo<T> foo) {
T t = foo.getOne();
/* do stuff */
foo.useOne(t);
}
Run Code Online (Sandbox Code Playgroud)
但是假设我想要分解工作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);
}
}
Run Code Online (Sandbox Code Playgroud)
这有点奇怪,因为类型参数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
...
}
Run Code Online (Sandbox Code Playgroud)
为了有用,在某些时候你将设置该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();
}
}
Run Code Online (Sandbox Code Playgroud)
您的问题与“捕获助手”解决的问题类似,但我不确定它是否可以应用于使用两种单独方法的第二个示例。您的第一个doStuff
方法肯定可以更好地编写为public void doStuff(Foo<?> foo)
,因为无论类型参数如何,它都可以工作Foo
。那么,“捕获助手”模式就会很有用。
更新:经过一番修改,扩展了 Goetz 捕获助手的想法,我想出了这个。里面看起来有点乱;从外面看,你不会怀疑任何事情。
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)