Java 通用对象重用
Java Generic Object Reuse
我有一个 class 层次结构,并想为层次结构中的每个 class 构建一个属性设置器列表。我要编写的代码类似于以下内容:
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
class Attribute<E, T> {
public final Class<T> dataType;
public final BiConsumer<E, T> setter;
public Attribute(final Class<T> dataType, final BiConsumer<E, T> setter) {
this.dataType = dataType;
this.setter = setter;
}
}
class Foo1 {
public static final List<Attribute<Foo1, ?>> foo1Attrs = new ArrayList<>();
static {
foo1Attrs.add(new Attribute<>(String.class, Foo1::setProp1));
}
public void setProp1(final String prop1) {
}
}
class Foo2 extends Foo1 {
// The following line results in an error
public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>(foo1Attrs);
static {
foo2Attrs.add(new Attribute<>(Integer.class, Foo2::setProp2));
}
public void setProp2(final Integer prop2) {
}
}
当我编译上面的代码时,出现错误:
error: incompatible types: cannot infer type arguments for ArrayList<>
public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>(foo1Attrs);
^
reason: inference variable E has incompatible bounds
equality constraints: Attribute<Foo2,?>
lower bounds: Attribute<Foo1,?>
where E is a type-variable:
E extends Object declared in class ArrayList
我明白为什么会出现上述错误。我的问题是,编译上述代码的典型模式是什么 运行?
我能弄清楚如何进行这项工作的唯一方法是在 Attribute
class 上创建一个复制构造函数,它采用 Attribute<? extends E, T>
,然后复制数据成员(指针)存储在属性 class 中到具有不同类型的第二个内存位置。对于应该相当于 C++ 中的 static_cast 的东西来说,这似乎真的很重。以下更改举例说明了这种方法:
class Attribute<E, T> {
...
public final BiConsumer<? super E, T> setter;
...
public Attribute(final Attribute<? super E, T> other) {
this.dataType = other.dataType;
this.setter = other.setter;
}
}
class Foo2 extends Foo1 {
public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>();
static {
for (Attribute<Foo1, ?> attr : foo1Attrs)
foo2Attrs.add(new Attribute<>(attr));
...
}
...
}
重申这个问题:是否有比上述方法更好的方法来解决此编译时错误?
由于 foo2Attrs
可以包含 Attribute<Foo1, ?>
,其中 Foo1
是 Foo2
的超类型,因此应将其声明为类型 List<Attribute<? super Foo2, ?>>
。这是有道理的,因为 Foo2
对象的属性可以由任何针对 Foo2
.
的超类的属性 setter 设置
同样,foo1Attrs
应声明为类型 List<Attribute<? super Foo1, ?>>
。
这消除了由第一个类型参数引起的编译错误,但是当您尝试编写类似 foo2Attrs.get(i).setter.accept(foo, 23)
的代码时仍然会有问题,因为 setter
是推断的因为类型 BiConsumer<? super Foo2, ?>
和整数 23
无法转换为第二个 ?
.
我有一个 class 层次结构,并想为层次结构中的每个 class 构建一个属性设置器列表。我要编写的代码类似于以下内容:
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
class Attribute<E, T> {
public final Class<T> dataType;
public final BiConsumer<E, T> setter;
public Attribute(final Class<T> dataType, final BiConsumer<E, T> setter) {
this.dataType = dataType;
this.setter = setter;
}
}
class Foo1 {
public static final List<Attribute<Foo1, ?>> foo1Attrs = new ArrayList<>();
static {
foo1Attrs.add(new Attribute<>(String.class, Foo1::setProp1));
}
public void setProp1(final String prop1) {
}
}
class Foo2 extends Foo1 {
// The following line results in an error
public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>(foo1Attrs);
static {
foo2Attrs.add(new Attribute<>(Integer.class, Foo2::setProp2));
}
public void setProp2(final Integer prop2) {
}
}
当我编译上面的代码时,出现错误:
error: incompatible types: cannot infer type arguments for ArrayList<> public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>(foo1Attrs); ^ reason: inference variable E has incompatible bounds equality constraints: Attribute<Foo2,?> lower bounds: Attribute<Foo1,?> where E is a type-variable: E extends Object declared in class ArrayList
我明白为什么会出现上述错误。我的问题是,编译上述代码的典型模式是什么 运行?
我能弄清楚如何进行这项工作的唯一方法是在 Attribute
class 上创建一个复制构造函数,它采用 Attribute<? extends E, T>
,然后复制数据成员(指针)存储在属性 class 中到具有不同类型的第二个内存位置。对于应该相当于 C++ 中的 static_cast 的东西来说,这似乎真的很重。以下更改举例说明了这种方法:
class Attribute<E, T> {
...
public final BiConsumer<? super E, T> setter;
...
public Attribute(final Attribute<? super E, T> other) {
this.dataType = other.dataType;
this.setter = other.setter;
}
}
class Foo2 extends Foo1 {
public static final List<Attribute<Foo2, ?>> foo2Attrs = new ArrayList<>();
static {
for (Attribute<Foo1, ?> attr : foo1Attrs)
foo2Attrs.add(new Attribute<>(attr));
...
}
...
}
重申这个问题:是否有比上述方法更好的方法来解决此编译时错误?
由于 foo2Attrs
可以包含 Attribute<Foo1, ?>
,其中 Foo1
是 Foo2
的超类型,因此应将其声明为类型 List<Attribute<? super Foo2, ?>>
。这是有道理的,因为 Foo2
对象的属性可以由任何针对 Foo2
.
同样,foo1Attrs
应声明为类型 List<Attribute<? super Foo1, ?>>
。
这消除了由第一个类型参数引起的编译错误,但是当您尝试编写类似 foo2Attrs.get(i).setter.accept(foo, 23)
的代码时仍然会有问题,因为 setter
是推断的因为类型 BiConsumer<? super Foo2, ?>
和整数 23
无法转换为第二个 ?
.