【问题标题】:What is the difference between a constructor and a builder when using generics?使用泛型时,构造函数和生成器有什么区别?
【发布时间】:2021-11-22 15:34:37
【问题描述】:

在使用Java编程时,我遇到了以下问题。

使用构造函数时:以下代码可以正常工作。

public class Generics<T> {

    private T data;

    public static <T> Generics<T> of(T data) {
        return new Generics<>(data);
    }

    public Generics(T data) {
        this.data = data;
    }
}

使用builder时:提示Object类型提供如下错误。

我使用了 Project Lombok 提供的构建器。

为什么上面代码中的通用生成器不起作用?

【问题讨论】:

  • 我用过龙目岛。您可以在上面的照片中看到@Builder。
  • @paiwmsn 您是在问每种模式何时最适合使用,还是只是简单地问如何使用 lombok 实现构建器模式?
  • 您正在使用Generics.builder(),但没有向构建器提供类型参数,因此它是一个原始类型
  • Generics&lt;T&gt;.builder() 怎么样?
  • 如果builder() 是通用静态方法,则更有可能是Generics.&lt;T&gt;builder()。我不知道龙目岛到底生成了什么。

标签: java generics lombok


【解决方案1】:

显然 Lombok 生成了一个静态泛型 builder() 方法。您可以在方法名称前使用&lt;T&gt; 指定泛型静态方法的泛型类型,如:

return Generics.<T>builder()
          .data(data)
          .build();

如果您在调用 builder() 时未指定泛型类型,则会得到原始类型,此时泛型类型推断不再起作用。

【讨论】:

    【解决方案2】:

    您需要显式添加泛型:return Generics.&lt;T&gt;builder() - 添加 &lt;T&gt;,一切都会好起来的。

    说明

    Java 是积极类型化的:每个表达式以及表达式的几乎每个部分都有一个实际类型; java 不允许事情一直处于不确定状态,直到以后;没有所谓的“中间人 - 嗯,我们会看到它的去向”。

    这意味着Generics.builder(),作为一个表达式,需要系统输入。构建器类同样需要&lt;T&gt;(它是Generics.GenericsBuilder&lt;X&gt; - 其中Builder 是泛型的静态内部类,定义为public static class GenericsBuilder&lt;X&gt;

    Java 不能直接得出您希望 X 和 T 为同一类型的结论。

    展望未来,它可以在没有您参与的情况下“自动”确定 X 应该是 T:它可以检查 .data(data) 调用,因为 data 方法在构建器中定义为:

    public GenericsBuilder<X> data(X data)
    

    因此,无论是data(变量)might be (it'sThere, given that it's the parameter defined asT data`)的类型,因此java可以得出X应该是T的结论。

    否则,java 可以进一步向前看,build(),并注意到它返回 X,并且正在由返回类型定义为 T 的方法返回,因此也使 java 有机会说:啊,X == T,对。

    但这不是 java 的工作原理。很大程度上是因为当你刚刚创建的那个构建器的X(声明public static &lt;X&gt; Generics.GenericsBuilder&lt;X&gt; builder()中的X)必须以某种形式保留时,即使弄清楚.data方法可能意味着什么也很难做到当解析器继续试图弄清楚其余部分的含义时,未知的边缘状态会暂时消失。鉴于 java 允许方法重载(2 个不同的方法具有相同的名称和相同数量的参数,但不同的参数类型,可能包含要引导的泛型) - 这将是一个组合爆炸,意味着您可以编写需要的 java 代码从字面上看,要解析几年。

    因此,java 不能那样工作,它必须从表达式 Generics.builder() 中确定 X 应该是什么单独,它显然不能。

    解决方案是明确地编写它,使用这种有点奇怪的语法:Generics.&lt;T&gt;builder()

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-30
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多