繁体   English   中英

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

[英]How to correctly type no-arg and withVar constructors in a generic class?

我正在研究(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;
  }
}

请注意, foobar本身不会更改类型。 <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);

是否有更好的方法对此进行编码,以便将泛型类型正确地传递到赋值运算符的右侧?

我可以执行此操作的唯一两种方法是添加一个用于指定类型的构造函数参数:

MyClass<Float> instance = new MyClass<>(0.f).withFoo(42).withBar("helloworld");

或添加“终端强制转换”方法:

public class MyClass<T> {
  // ...

  public MyClass() { ... }

  public <U> MyClass<U> cast() {
    MyClass<U> copy = new MyClass<>();
    return copy.withFoo(foo).withBar(bar);
  }

  public MyClass<T> withFoo(int foo) { ... }
  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");

但是我想您可能真的不想为每种可能的类型都拥有工厂方法。


但是请注意,如果您无需向将MyClass实例与其类型参数相关联的cast方法(或构造函数)提供任何东西就能做到这一点,则您实际上不需要在类上使用类型变量。

您可以将类型变量仅推送到需要该类型变量的方法上:

public class MyClass {
  // ...

  public <T> T doSomethingToSpecificType(List<T> list, T arg) {
    // do something type-specific.
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM