Java 泛型的类型别名

2022-09-01 04:42:00

我在Java中有一组相当复杂的泛型类。例如,我有一个接口

interface Doable<X,Y> {
  X doIt(Y y);
}

和实现

class DoableImpl implements Doable<Foo<Bar<Baz,Qux>>,Foo<Bar<Zot,Qux>>> {
  Foo<Bar<Baz,Qux>> doIt(Foo<Bar<Zot,Qux>> fooBZQ) { ... }
}

在实际实现中,有相当多的方法等等,一遍又一遍地出现。(信不信由你,泛型类型比这更痛苦。我在本例中简化了它们。DoableFoo<Bar<Baz,Qux>>

我想简化这些,以节省自己的打字时间并减轻眼睛的压力。我想要的是有一个简单的“类型别名”,等等,比如说和。Foo<Bar<Baz,Qux>>FooBBQFooBZQ

我目前的想法是定义包装类:

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) { ... }
}

这很有效,但它有一些缺点:

  1. 我们需要为每个通用实例定义单独的包装器。包装类很短且风格化,但我无法找到一种宏化它们的方法。
  2. 我们有转换开销(概念上,如果不是操作上)调用并在 和 之间转换。例如,如果调用某个期望的库例程(实际实现确实如此),我们最终会得到类似的东西valueOftoGenericFooBBQFoo<Bar<Baz,Qux>>doItFoo<Bar<Zot,Qux>>

    return FooBBQ.valueOf( libraryCall( fooBZQ.toGeneric() ) )
    

    我们原本会拥有的地方

    return libraryCall(fooBZQ);
    

有没有其他方法可以获得我想要的“类型别名”行为?也许使用一些第三方宏工具集?或者我是否需要接受我将不得不做很多类型,一种方式(在实现中使用泛型类型)还是另一种方式(为它们编写包装器)?也许有这么多通用参数飞来飞去只是一个坏主意,我需要重新思考这个问题?

[更新]好吧,我禁止任何进一步的“不要那样做”的答案。把它作为一个在我的问题域中具有真正价值的给定值(Pete Kirkham可能是对的,它有足够的值来获得具有描述性名称的正确包装器类)。但这是一个编程问题;不要试图把问题定义掉。Foo<Bar<Baz,Qux>>


答案 1

如果你想要全类型安全,我认为如果没有某种包装类,你就无法做得更好。但是,为什么不让这些类继承/实现原始的泛型版本,如下所示:

public class FooBBQ extends Foo<Bar<Baz,Qux>> {
...
}

这消除了对方法的需求,并且在我看来,更清楚的是,它只是一个类型别名。此外,可以在没有编译器警告的情况下转换为泛型类型。如果可能的话,我个人倾向于制作接口,即使实现中会发生一些代码重复。toGeneric()FooBBQFoo, Bar, Baz...

现在,如果不知道具体的问题领域,很难说你是否需要,比如说,就像你的例子一样,或者也许一个:FooBBQ

public class FooBar<X, Y> extends Foo<Bar<X, Y>> {
...
}

另一方面,你有没有想过简单地配置Java编译器,不显示一些通用警告,而只是省略泛型定义的部分?或者,使用战略性放置?换句话说,你能只做“部分泛化”吗:@SuppressWarnings("unchecked")DoableImpl

class DoableImpl implements Doable<Foo<Bar>>,Foo<Bar>> {
    Foo<Bar> doIt(Foo<Bar> foobar) { ... } 
}

并忽略警告以减少代码混乱?同样,如果没有具体的例子,很难决定,但这是你可以尝试的另一件事。


答案 2

Scala对类型别名有很好的支持。例如:

type FooBBQ = Foo[Bar[Baz,Qux]]

我意识到,如果你没有选择切换到Scala,这个答案将没有帮助。但是,如果您确实可以选择切换,则可能会更容易。


推荐