Java 列表中不兼容的等式约束
Java Incompatible equality constraint in list
我有一个多级 class 结构,我想将它们的实现传递给一个可以调用它们的函数,但是我得到一个 Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO
错误。
代码如下:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
我尝试实现的更详细的示例:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
@Override
public void func2() {
// comes from Interf
}
@Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
@Override
public void func2() {
// comes from Interf
}
@Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
确切的错误信息:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
我需要函数 func
中的列表来扩展 DTO
并实现 Interf
,因为我在它们上面调用了某些函数。
为什么会这样?如果我更改 func
的签名并仅传递一个 DAO
,它工作正常,但我需要它与多个一起工作。
这里我有什么选择?
我试过多个java版本(1.8+),都一样。
你的函数应该这样声明:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
请注意,我将 List<DAO<T>>
更改为 List<DAO<? extends T>>
。这是因为表达式 Arrays.asList(daoImpl1, daoImpl2)
产生类型
的值
List<DAO<? extends DTO & Interf>>
(当然,这不是 Java 中类型的真正语法。Java 中没有交集类型的语法,但 Java 在执行类型时确实知道它们推理,如果你使用 var
,你可以在你的代码中使用这些类型。我在这里使用这个符号只是为了说明目的。)
如果你知道PECS, you'll know that this is a list of DAOs that produces DTO & Interf
s/T
s, but does not consume DTO & Interf
s/T
s. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
这样做的原因很直观。想象一下,如果 DAO
只是 T
.
的容器
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
如果 Arrays.asList(daoImpl1, daoImpl2)
生成了 DAO<DTO & Interf>
的列表(没有 extends
或 super
),您可以调用 getT
andsetT
关于元素列表!能够调用 setT
是特别危险的——你可以这样做:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
如果 someRandomNumber
恰好是 1
,我们得到第二个元素,即 DAO<SubDTO2>
怎么办?将 SubDTO
放入其中会破坏整个 type-safety 泛型。
对像 [daoImpl1, daoImpl2]
这样的列表的元素唯一 type-safe 的事情就是将它们用作 DTO & Interf
s 的生产者,因此类型被标记为 ? extends DTO & Interf
.这意味着如果您在 DAO
上有任何接受 T
的方法,您将无法在此列表 * 的元素上调用它们。
另请注意,以防万一我不清楚,不仅仅是列表是生产者 - 该列表既是 DAO
的生产者又是消费者。只是列表中的 DAO
是他们 T
的生产者。
* 除了传递 null
s.
我有一个多级 class 结构,我想将它们的实现传递给一个可以调用它们的函数,但是我得到一个 Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO
错误。
代码如下:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
我尝试实现的更详细的示例:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
@Override
public void func2() {
// comes from Interf
}
@Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
@Override
public void func2() {
// comes from Interf
}
@Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
确切的错误信息:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
我需要函数 func
中的列表来扩展 DTO
并实现 Interf
,因为我在它们上面调用了某些函数。
为什么会这样?如果我更改 func
的签名并仅传递一个 DAO
,它工作正常,但我需要它与多个一起工作。
这里我有什么选择?
我试过多个java版本(1.8+),都一样。
你的函数应该这样声明:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
请注意,我将 List<DAO<T>>
更改为 List<DAO<? extends T>>
。这是因为表达式 Arrays.asList(daoImpl1, daoImpl2)
产生类型
List<DAO<? extends DTO & Interf>>
(当然,这不是 Java 中类型的真正语法。Java 中没有交集类型的语法,但 Java 在执行类型时确实知道它们推理,如果你使用 var
,你可以在你的代码中使用这些类型。我在这里使用这个符号只是为了说明目的。)
如果你知道PECS, you'll know that this is a list of DAOs that produces DTO & Interf
s/T
s, but does not consume DTO & Interf
s/T
s. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
这样做的原因很直观。想象一下,如果 DAO
只是 T
.
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
如果 Arrays.asList(daoImpl1, daoImpl2)
生成了 DAO<DTO & Interf>
的列表(没有 extends
或 super
),您可以调用 getT
andsetT
关于元素列表!能够调用 setT
是特别危险的——你可以这样做:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
如果 someRandomNumber
恰好是 1
,我们得到第二个元素,即 DAO<SubDTO2>
怎么办?将 SubDTO
放入其中会破坏整个 type-safety 泛型。
对像 [daoImpl1, daoImpl2]
这样的列表的元素唯一 type-safe 的事情就是将它们用作 DTO & Interf
s 的生产者,因此类型被标记为 ? extends DTO & Interf
.这意味着如果您在 DAO
上有任何接受 T
的方法,您将无法在此列表 * 的元素上调用它们。
另请注意,以防万一我不清楚,不仅仅是列表是生产者 - 该列表既是 DAO
的生产者又是消费者。只是列表中的 DAO
是他们 T
的生产者。
* 除了传递 null
s.