使用泛型时,构造函数和构建器之间有什么区别?
What is the difference between a constructor and a builder when using generics?
在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 提供的构建器。
为什么上面代码中的生成器泛型不起作用?
显然 Lombok 生成了一个静态泛型 builder()
方法。您可以在方法名称前使用 <T>
指定泛型静态方法的泛型类型,如:
return Generics.<T>builder()
.data(data)
.build();
如果您在调用 builder()
时未指定泛型类型,您将获得原始类型,此时泛型类型推断将不再起作用。
您需要显式添加泛型:return Generics.<T>builder()
- 添加 <T>
一切都会好起来的。
说明
Java 是强类型的:每个表达式以及表达式的几乎每个部分都有一个实际类型; java 不允许事后搁置;没有所谓的“中间件 - 嗯,我们会看到它的去向”。
即Generics.builder()
,作为一个表达式,需要系统打字。构建器 class 需要 <T>
一样(它是 Generics.GenericsBuilder<X>
- 其中 Builder
是泛型的静态内部 class,定义为 public static class GenericsBuilder<X>
.
Java 不能直接得出您希望 X 和 T 为同一类型的结论。
展望未来,它可以计算出 X 应该是 T 'automatically',而无需您的参与:它可以检查 .data(data)
调用,前提是定义了 data
方法在生成器中为:
public GenericsBuilder<X> data(X data)
因此,无论什么类型 data
(变量)might be (it's
There, given that it's the parameter defined as
T 数据`),因此,java 可以得出 X 应该是 T 的结论.
否则,java 可以看得更远,到 build()
,并注意这个 returns X
,并且正在 returned通过一个 return 类型被定义为 T
的方法,因此也给 java 机会说:啊,X == T,对。
但这不是 java 的工作方式。在很大程度上是因为当您刚刚创建的构建器的 X
(声明 public static <X> Generics.GenericsBuilder<X> builder()
中的 X
时,即使弄清楚 .data
方法可能意味着什么也很难做到) 必须在某种未知的边缘状态中保留一段时间,因为解析器会继续尝试弄清楚其余部分的含义。鉴于 java 允许方法重载(2 个不同的方法具有相同的名称和相同数量的参数,但不同的参数类型,可能包含泛型来引导) - 这将是一个组合爆炸,意味着你可以写java 需要数年才能解析的代码。
因此,java 不能那样工作,它必须从表达式 Generics.builder()
中单独 确定 X
应该是什么 ,显然不能。
解决方案是使用这种有点奇特的语法明确地编写它:Generics.<T>builder()
.
在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 提供的构建器。
为什么上面代码中的生成器泛型不起作用?
显然 Lombok 生成了一个静态泛型 builder()
方法。您可以在方法名称前使用 <T>
指定泛型静态方法的泛型类型,如:
return Generics.<T>builder()
.data(data)
.build();
如果您在调用 builder()
时未指定泛型类型,您将获得原始类型,此时泛型类型推断将不再起作用。
您需要显式添加泛型:return Generics.<T>builder()
- 添加 <T>
一切都会好起来的。
说明
Java 是强类型的:每个表达式以及表达式的几乎每个部分都有一个实际类型; java 不允许事后搁置;没有所谓的“中间件 - 嗯,我们会看到它的去向”。
即Generics.builder()
,作为一个表达式,需要系统打字。构建器 class 需要 <T>
一样(它是 Generics.GenericsBuilder<X>
- 其中 Builder
是泛型的静态内部 class,定义为 public static class GenericsBuilder<X>
.
Java 不能直接得出您希望 X 和 T 为同一类型的结论。
展望未来,它可以计算出 X 应该是 T 'automatically',而无需您的参与:它可以检查 .data(data)
调用,前提是定义了 data
方法在生成器中为:
public GenericsBuilder<X> data(X data)
因此,无论什么类型 data
(变量)might be (it's
There, given that it's the parameter defined as
T 数据`),因此,java 可以得出 X 应该是 T 的结论.
否则,java 可以看得更远,到 build()
,并注意这个 returns X
,并且正在 returned通过一个 return 类型被定义为 T
的方法,因此也给 java 机会说:啊,X == T,对。
但这不是 java 的工作方式。在很大程度上是因为当您刚刚创建的构建器的 X
(声明 public static <X> Generics.GenericsBuilder<X> builder()
中的 X
时,即使弄清楚 .data
方法可能意味着什么也很难做到) 必须在某种未知的边缘状态中保留一段时间,因为解析器会继续尝试弄清楚其余部分的含义。鉴于 java 允许方法重载(2 个不同的方法具有相同的名称和相同数量的参数,但不同的参数类型,可能包含泛型来引导) - 这将是一个组合爆炸,意味着你可以写java 需要数年才能解析的代码。
因此,java 不能那样工作,它必须从表达式 Generics.builder()
中单独 确定 X
应该是什么 ,显然不能。
解决方案是使用这种有点奇特的语法明确地编写它:Generics.<T>builder()
.