为什么使用 `field(select(...))` 和 `select(...).asField()` 有区别?

问题描述 投票:0回答:1

在下面的代码中,我的直觉是变量 x 和 y 具有相同的类型:

var x = field(select(T.A).from(T));
var y = select(T.A).from(T).asField();

如果我要求 IntelliJ 将

var
替换为显式类型,我会得到:

Field<String> x = field(select(T.A).from(T));
Field<Object> y = select(T.A).from(T).asField();

我相信 IntelliJ 而不是我的直觉,所以现在我想知道为什么。 这是 Java 的限制吗? jOOQ 中的错误?还有别的吗?

以下是

field
asField
的方法签名供参考:

public static <T> Field<T> field(Select<? extends Record1<T>> select);
public <T> Field<T> asField();
jooq
1个回答
0
投票

DSL.field()
是一个通用方法,可以捕获其类型变量
T
FieldLike.asField()
无法根据您使用的
FieldLike
的任何子类型(包括
Select<R>
)捕获类型变量。由于历史性错误,它仍然是通用记录,这允许您在使用站点不安全地转换
T
类型。但这只是一个不安全的转换,而不是正确捕获您想要的类型
String

由于 jOOQ API 是现在设计的,因此无法在 Java 中修复

asField()
方法,因为
R
中的类型变量
Select<R>
并不知道它是否实际上是一个
Record1<T>
(标量子查询),或其他任何东西。

其他语言可以在其泛型类型边界上添加额外的“约束”,或者允许使用扩展方法来给人一种

.asField()
“方法”的感觉,这实际上只是一个
static
函数,如
DSL.field()
,但在第一个参数上带有后缀符号。

Java 中唯一有效的解决方案是“重载”

Select
类型:

  • Select1<T1, R extends Record1<T1>> extends Select<R>
  • Select2<T1, T2, R extends Record2<T1, T2>> extends Select<R>
  • Select3<T1, T2, T3, R extends Record3<T1, T2, T3>> extends Select<R>
  • ...

但这会在整个 jOOQ API 中产生大量额外的、不良的副作用,这就是这个想法被拒绝并引入

DSL.field()
的原因。

逻辑上,这两种方法是等效的,但

DSL.field()
更优越,因为它捕获了正确的类型。

© www.soinside.com 2019 - 2024. All rights reserved.