猿问

如何在泛型类中正确键入 no-arg 和 withVar 构造函数?

我正在研究一个(Java 8+)类,我想使用一种“构建器”模式构建它,在该模式中,您将无参数构造函数链接到一个或多个返回相同对象的设置器。基本上这是我的课:


public class MyClass {

  private int foo;

  private String bar;


  public MyClass() {

    System.out.println("initializing instance of MyClass");

  }

  public MyClass withFoo(int foo) {

    this.foo=foo;

    return this;

  }

  public MyClass withBar(String bar) {

    this.bar = bar;

    return this;

  }

}

您初始化它的典型方法是


MyClass anInstance = new Myclass().withFoo(42).withBar("helloworld");

这是一个很好的模式,但我以前从未将它用于泛型类。现在我想泛化我的班级。我对类签名和构造函数、withFoo 和 withBar 方法进行了更改:


public class MyClass<T> {

  private int foo;

  private String bar;


  public MyClass() {

    System.out.println("initializing instance of MyClass");

  }

  public MyClass<T> withFoo(int foo) {

    this.foo=foo;

    return this;

  }

  public MyClass<T> withBar(String bar) {

    this.bar = bar;

    return this;

  }

}

请注意,foo它们bar自己不会改变类型。任何类型<T>都不会通过方法传入withVar()

我有一些线索表明这不是最好的方法。标准的无参数构造函数似乎工作正常:

  • 工作正常: MyClass<Float> myInstance = new MyClass<>();

但是,如果我添加一个withVar函数,我会在编译时遇到错误(java:不兼容的类型:MyClass 无法转换为 MyClass)。

  • 不会编译: MyClass<Float> myInstance = new MyClass<>().withFoo(42);

我可以通过两次指定类型来使其工作,如下所示:

  • 工作正常: MyClass<Float> myInstance = new MyClass<Float>().withFoo(42);

有没有更好的方法来编写代码,以便将泛型类型正确地传递到赋值运算符的右侧?


摇曳的蔷薇
浏览 135回答 1
1回答

凤凰求蛊

我能做到这一点的唯一两种方法是添加一个指定类型的构造函数参数:MyClass<Float> instance = new MyClass<>(0.f).withFoo(42).withBar("helloworld");或者通过添加“终端投射”方法:public class MyClass<T> {&nbsp; // ...&nbsp; public MyClass() { ... }&nbsp; public <U> MyClass<U> cast() {&nbsp; &nbsp; MyClass<U> copy = new MyClass<>();&nbsp; &nbsp; return copy.withFoo(foo).withBar(bar);&nbsp; }&nbsp; public MyClass<T> withFoo(int foo) { ... }&nbsp; public MyClass<T> withBar(String bar) { ... }}然后你可以像这样调用它:MyClass<Float> instance = new MyClass<>().withFoo(42).withBar("helloworld").cast();第三种方法是提供一个MyClass<Float>专门用于创建实例的工厂方法:static MyClass<Float> newFloatInstance() { return new MyClass<>(); }然后你可以像这样调用它:MyClass<Float> instance = newFloatInstance().withFoo(42).withBar("helloworld");但我猜你可能真的不想为每种可能的类型都使用工厂方法。但是请注意,如果您能够在不向 cast 方法(或构造函数)提供将其实例与其MyClass类型参数相关联的情况下执行此操作,那么您实际上不需要类上的类型变量。您可以将类型变量推送到需要该类型变量的方法上:public class MyClass {&nbsp; // ...&nbsp; public <T> T doSomethingToSpecificType(List<T> list, T arg) {&nbsp; &nbsp; // do something type-specific.&nbsp; }}
随时随地看视频慕课网APP

相关分类

Java
我要回答