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, ?>,其中 Foo1Foo2 的超类型,因此应将其声明为类型 List<Attribute<? super Foo2, ?>>。这是有道理的,因为 Foo2 对象的属性可以由任何针对 Foo2.

的超类的属性 setter 设置

同样,foo1Attrs 应声明为类型 List<Attribute<? super Foo1, ?>>

这消除了由第一个类型参数引起的编译错误,但是当您尝试编写类似 foo2Attrs.get(i).setter.accept(foo, 23) 的代码时仍然会有问题,因为 setter 是推断的因为类型 BiConsumer<? super Foo2, ?> 和整数 23 无法转换为第二个 ?.