Chr*_*way 30 java generics casting
我在Java中有一套相当复杂的泛型类.例如,我有一个界面
interface Doable<X,Y> {
X doIt(Y y);
}
Run Code Online (Sandbox Code Playgroud)
和实施
class DoableImpl implements Doable<Foo<Bar<Baz,Qux>>,Foo<Bar<Zot,Qux>>> {
Foo<Bar<Baz,Qux>> doIt(Foo<Bar<Zot,Qux>> fooBZQ) { ... }
}
Run Code Online (Sandbox Code Playgroud)
在实际实现中,Doable有不少方法Foo<Bar<Baz,Qux>>等等,一遍又一遍地出现.(信不信由你,通用类型比这更痛苦.我为这个例子简化了它们.)
我想简化这些,以节省自己的打字和缓解眼睛的压力.我想是有一个简单的"类型的别名"对Foo<Bar<Baz,Qux>>等的,说FooBBQ和FooBZQ.
我目前的想法是定义包装类:
class FooBBQ {
public static FooBBQ valueOf(Foo<Bar<Baz,Qux>> fooBBQ) {
return new FooBBQ(fooBBQ);
}
private Foo<Bar<Baz,Qux>> fooBBQ;
private FooBBQ(Foo<Bar<Baz,Qux>> fooBBQ) {
this.fooBBQ = fooBBQ;
}
public Foo<Bar<Baz,Qux>> toGeneric() {
return fooBBQ;
}
}
class FooBZQ { /* pretty much the same... */ }
class DoableImpl implements Doable<FooBBQ,FooBZQ> {
FooBBQ doIt(FooBZQ fooBZQ) { ... }
}
Run Code Online (Sandbox Code Playgroud)
这很好用,但它有一些缺点:
我们有翻译的开销(概念,如果没有操作性)调用的valueOf和toGeneric之间进行转换FooBBQ和Foo<Bar<Baz,Qux>>.例如,如果doIt调用某个期望a的库例程Foo<Bar<Zot,Qux>>(实际的实现),我们最终会得到类似的结果
return FooBBQ.valueOf( libraryCall( fooBZQ.toGeneric() ) )
Run Code Online (Sandbox Code Playgroud)
我们原本应该去的地方
return libraryCall(fooBZQ);
Run Code Online (Sandbox Code Playgroud)有没有其他方法来获得我想要的"类型别名"行为?也许使用一些第三方宏工具集?或者我是否需要接受我将不得不进行大量的输入,一种方式(使用实现中的泛型类型)或另一种方式(为它们编写包装器)?也许有这么多通用参数飞来飞去只是一个坏主意,我需要重新思考这个问题?
[更新]好的,我禁止任何进一步的"不要那样做"的答案.把它当作Foo<Bar<Baz,Qux>>在我的问题域中具有真正价值的给定(Pete Kirkham可能是正确的,它具有足够的价值来获得具有描述性名称的正确包装类).但这是一个编程问题; 不要试图去解决问题.
jav*_*ook 10
如果你想要完全的类型安全,我认为如果没有某种包装类,你可以做得更好.但是,为什么不让这些类继承/实现原始的泛型版本,如下所示:
public class FooBBQ extends Foo<Bar<Baz,Qux>> {
...
}
Run Code Online (Sandbox Code Playgroud)
这消除了对toGeneric()方法的需要,在我看来,它更清楚,它只是一种类型别名.此外,可以在FooBBQ没有编译器警告的情况下转换泛型类型.Foo, Bar, Baz...如果可能的话,即使在实现中发生某些代码重复,我个人也会优先选择接口.
现在,在不知道具体问题域的情况下,很难说您是否需要,比如说FooBBQ,在您的示例中,或者可能是:
public class FooBar<X, Y> extends Foo<Bar<X, Y>> {
...
}
Run Code Online (Sandbox Code Playgroud)
另一方面,您是否考虑过简单地配置Java编译器以不显示某些通用警告,而只是省略通用定义的部分?或者,战略性地使用@SuppressWarnings("unchecked")?换句话说,你能DoableImpl只做"部分通用化":
class DoableImpl implements Doable<Foo<Bar>>,Foo<Bar>> {
Foo<Bar> doIt(Foo<Bar> foobar) { ... }
}
Run Code Online (Sandbox Code Playgroud)
并且为了减少代码混乱而忽略警告?再说一次,如果没有一个具体的例子,很难做出决定,但这是你可以尝试的另一件事.
Scala对类型别名有很好的支持.例如:
type FooBBQ = Foo[Bar[Baz,Qux]]
Run Code Online (Sandbox Code Playgroud)
我意识到如果您没有切换到Scala的选项,这个答案将没有用.但如果您确实可以选择切换,那么您可能会有更轻松的时间.
也许拥有这么多通用参数只是一个坏主意,我需要重新考虑这个问题?
很有可能。是否需要专门研究 8 个维度的“Doit”?
在很多情况下,这些类型并不存在于真空中,您应该考虑您的“包装器”代表什么域对象,而不是将它们用作编码的便利。