【问题标题】:How can I resolve this situation with Java Generics?如何使用 Java 泛型解决这种情况?
【发布时间】:2021-03-07 05:51:22
【问题描述】:

我有以下类层次结构:

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(Class) 未定义”。无法将 `MyObject.class` 转换为 `Class>`。

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

  1. public class AllObjectContainer extends MyObjectContainer&lt;MyObject&lt;?&gt;&gt; 更改为public class AllObjectContainer extends MyObjectContainer&lt;MyObject&gt;

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

或者我可以通过

启用投射
  1. protected MyObjectContainer(Class&lt;T&gt; valueType) { 更改为protected MyObjectContainer(Class&lt;? extends T&gt; valueType) {(添加? extends
  2. super(MyObject.class) 更改为super((Class&lt;? extends MyObject&lt;?&gt;&gt;) MyObject.class)

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

有没有更好的解决方案?

【问题讨论】:

标签: java generics inheritance reflection


【解决方案1】:

所以,MyClass.class 的类型是 Class&lt;MyClass&gt; 而不是 Class&lt;MyClass&lt;?&gt;&gt;

这确实是一个关于反射的问题。

通常解决反射问题的好方法是不使用反射。

我建议去掉Class的使用,换成你想要的操作界面。然后,如果您愿意,您可以在该接口的特定实现中放置反射讨厌。

【讨论】:

    【解决方案2】:

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

    然而,就我而言,不可能完全摆脱反射,因为 Class 值被传递给另一个不受我控制的类 - 这是否好是另一个问题(我猜,答案是否定的),但不在这个问题的范围内。

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

    1. 从构造函数中移除了valueType 参数
    2. 已将protected abstract Class&lt;T&gt; 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;
        }
    }
    

    双重演员并不漂亮,我完全意识到这一点。然而它在一个狭窄的地方,很明显可以投射并且它修复了“无法投射”的错误。

    【讨论】:

      猜你喜欢
      • 2011-04-19
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      • 1970-01-01
      • 2023-03-25
      相关资源
      最近更新 更多