【问题标题】:Generics and type inference for a generic factory泛型工厂的泛型和类型推断
【发布时间】:2013-11-20 15:34:48
【问题描述】:

对于此问题中任何不好的英语语言,请提前道歉。

我想创建一种工厂,它只能创建由具体工厂实例类实现的列表中定义的类的实例。首先,我定义了这个接口:

public interface ValuesSystem {

    public interface AllowedValue<T extends Class<? extends SystemValue>>{};

    AllowedValue<Class<? extends SystemValue>> getAllowedValue(Enum<?> id);

    Map<? extends Enum<?>, AllowedValue<Class<? extends SystemValue>>> getAllowedValues();

    <T extends SystemValue> T create(AllowedValue<Class<T>> allowedClass, ValueData data) throws InvalidValueException;
}

接口 AllowedValue 只是一个“标记包装器”接口,它使用泛型来定义一个“允许”由我的工厂创建的类实例。

getAllowedValue 是一种方法,用于使用来自实现此接口的具体类的内部枚举从我的允许类“列表”中获取包装的允许类实例(具体类的示例将出现)。

create 方法旨在最终创建一个我在 allowedClass 参数中给出的允许 Class 实例的实例。

这是一个实现此接口的具体类的示例:

public class BasicValueSystem implements ValuesSystem {

    public BasicValueSystem() {
        super();
        allowedValues = (Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>>) getAllowedValues();
    }

    public static enum VALUES_ID {
        MODIFIER
    }

    private static Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>> allowedValues;

    private class BasicAllowedValue<T extends Class<? extends SystemValue>>
            implements AllowedValue<Class<? extends SystemValue>> {

    }

    @Override
    public <T extends SystemValue> T create(
            AllowedValue<Class<T>> allowedClass, ValueData data)
                throws InvalidValueException {
        if (!(allowedClass instanceof BasicAllowedValue)) {
            throw new InvalidValueException();
        }
        return null;
    }

    @Override
    public AllowedValue<Class<? extends SystemValue>> getAllowedValue(Enum<?> id) {
        return allowedValues.get(id);
    }

    @Override
    public Map<? extends Enum<?>, AllowedValue<Class<? extends SystemValue>>> getAllowedValues() {
        Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>> allowed = new EnumMap<VALUES_ID, AllowedValue<Class<? extends SystemValue>>>(VALUES_ID.class);
        allowed.put(VALUES_ID.MODIFIER, new BasicAllowedValue<Class<ModifierValue>>());
        return allowed;
    }
}

目前 create 方法返回 null,但问题出在其他地方,这不是我的问题的重点

当我尝试使用以下代码创建我的“允许”值实例之一的实例时出现问题:

BasicValueSystem bvs = new BasicValueSystem();
AllowedValue<Class<? extends SystemValue>> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());

编译器告诉我:

The method create(ValuesSystem.AllowedValue<Class<T>>, ValueData) in the type BasicValueSystem is not applicable for the arguments (ValuesSystem.AllowedValue<Class<? extends SystemValue>>, ModifierValueData)

我想我错过了一些关于泛型的类型推断的东西。

谁能解释一下 create 方法签名在这种情况下不适用以及如何解决?

提前感谢您抽出宝贵时间。

【问题讨论】:

  • 这里VALUES_ID枚举的作用我不是很明白。目前,您的 allowedValues 地图仅包含一个条目。你能解释一下吗?顺便说一句,你为什么不让你的类自己通用?
  • 在示例中是的,它包含一个唯一的枚举值。这只是为了简化。枚举和 EnumMap 旨在包含多个值(对于枚举)和 AllowedValue 对象(对于 EnumMap)
  • 那么您是否遍历枚举 values() 以向地图添加条目?你能发布你的getAllowedValues 的实际样子吗?
  • 如果我没记错的话,getAllowedValues 方法在我的 BasicValueSystem 类示例中
  • 对不起,我的意思是,你能把它扩展一下。目前尚不清楚您维护地图的方式。你想每个枚举都有一个映射,包含所有允许的值吗?如果单个枚举值有多个允许值怎么办?

标签: java generics type-inference


【解决方案1】:

请注意,public interface AllowedValue&lt;T extends Class&lt;? extends SystemValue&gt;&gt; 没有多大意义。 T 的唯一有效类型是 Class&lt;? extends SystemValue&gt;,因为类 Class 是 final 并且不能有子类。所以你可以用interface AllowedValue&lt;Class&lt;? extends SystemValue&gt;&gt; 替换它而不改变语义,但你真正的意思(恕我直言)是interface AllowedValue&lt;T extends SystemValue&gt;。不要在类型签名中乱用Class。接口可能仍然有引用Class&lt;T&gt;的方法。

public interface ValuesSystem {

  public interface AllowedValue<T extends SystemValue>{};

  AllowedValue<? extends SystemValue> getAllowedValue(Enum<?> id);

  public <T extends SystemValue> T create
                     (AllowedValue<T> allowedClass, ValueData data);
}

相应地调整实现,BasicAllowedValue 变为

private class BasicAllowedValue<T extends SystemValue> implements AllowedValue<T>

那么你使用代码的问题就消失了。

BasicValueSystem bvs = new BasicValueSystem();
AllowedValue<? extends SystemValue> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());

将编译。


请注意,如果AllowedValue 只保留一个没有方法的标记接口,则没有必要,Class&lt;T&gt; 已经完成了这个角色。这样做也可以:

public interface ValuesSystem {
  Class<? extends SystemValue> getAllowedValue(Enum<?> id);
  public <T extends SystemValue> T create(Class<T> allowedClass, ValueData data);
}

BasicValueSystem bvs = new BasicValueSystem();
Class<? extends SystemValue> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());

【讨论】:

  • 谢谢它有效,我现在的工作是理解我的错误。谢谢你的时间
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多