Warm tip: This article is reproduced from serverfault.com, please click

其他-如何使用Java泛型解决这种情况?

(其他 - How can I resolve this situation with Java Generics?)

发布于 2020-11-24 12:35:46

我有以下类层次结构:

public abstract class MyParentObject {}
public abstract class MyObject<T> extends MyParentObject {}

public abstract class MyParentContainer<T extends MyParentObject> {
    private Class<T> valueType;
    protected MyParentContainer(Class<T> valueType) {
        this.valueType = valueType;
    }
}
public abstract class MyObjectContainer<T extends MyObject<?>> extends MyParentContainer<T> {
    protected MyObjectContainer(Class<T> valueType) {
        super(valueType);
    }
}

到目前为止,这个工作正常。有几个子类MyObject和几个容器类,其中一些子类为valueType,例如

public class IntObject extends MyObject<Integer> {}
public class IntContainer extends MyObjectContainer<IntObject> {
    public IntContainer() {
        super(IntObject.class);
    }
}

现在,我需要实现一个容器,尽管该容器可与的子集混合使用MyObject

public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
    public AllObjectContainer() {
        super(MyObject.class); // compile error here
    }
}

这不会编译,因为“未定义构造函数MyObjectContainer <MyObject>(Class)”。无法将“ MyObject.class”转换为“ Class>”。

为了解决这个问题,我可以使用原始类型:

  1. 更改public class AllObjectContainer extends MyObjectContainer<MyObject<?>>public class AllObjectContainer extends MyObjectContainer<MyObject>

尽管由于类型擦除而产生了后果,所以我不喜欢这种解决方案。

或者,我可以通过以下方式启用投射

  1. 更改protected MyObjectContainer(Class<T> valueType) {protected MyObjectContainer(Class<? extends T> valueType) {(添加? extends
  2. 更改super(MyObject.class)super((Class<? extends MyObject<?>>) MyObject.class)

此方法有效,但是强制转换标记为未选中,并且更改MyMiddleContainer-Constructor会对扩展它的其他类具有潜在的副作用。

有更好的解决方案吗?

Questioner
sina
Viewed
11
sina 2020-11-30 17:02:46

关于反射的评论以及此代码不是最佳实现的标志,这些评论是真实有效的,偶然发现此答案的每个人都应阅读并考虑它们

但是,在我的情况下,不可能完全消除反射,因为该Class值已传递给另一个不受我控制的类-是否好是另一个问题(我想答案是“否”)。 '),但不在此问题的范围内。

我通过以下方式解决了我的问题:

  1. valueType从构造函数中删除了参数
  2. 添加protected abstract Class<T> getValueType();MyParentContainer

然后,我通过以下方式实现了该方法:

public class IntContainer extends MyObjectContainer<IntObject> {
    protected Class<T> getValueType() {
        return IntObject.class;
    }
}

public class AllObjectContainer extends MyObjectContainer<MyObject<?>> {
    protected Class<T> getValueType() {
        return (Class<MyObject<?>>) (Class<?>) MyObject.class;
    }
}

双重演员表并不漂亮,我完全意识到这一点。但是它处于受限的位置,显然可以进行投射,并且可以修复“无法投射”错误。