1

在下面的代码中,类型参数D可以是 aList<Byte>或 a List<List<Byte>>(它是Fields<?, ?, D>接口中的第三个泛型参数,但我仍然可以在此处省略它 - 但它也存在于方法的返回类型中)。似乎无法找到一种方法来告诉编译器这一点 -Unchecked cast在标记的行中获取警告//*

public static <D, K, T extends Enum<T> & Fields<?, ?, D>> List<EnumMap<T, D>> 
        getEntries(InputStream is, Class<T> fields) throws IOException {
    final List<List<Byte>> entries = new ArrayList<List<Byte>>();
    // populate "entries"
    final boolean hasLists = hasLists(fields);
    List<K> daBytes;
    if (hasLists) {
        daBytes = (List<K>) new ArrayList<EnumMap<T, List<List<Byte>>>>(); //*
    } else {
        daBytes = (List<K>) new ArrayList<EnumMap<T, List<Byte>>>(); //*
    }
    final int numOfEntries = entries.size();
    for (int currentEntry = 0; currentEntry < numOfEntries; ++currentEntry) {
        // add an element in daBytes for this currentEntry
        if (hasLists) {
            daBytes.add((K) new EnumMap<T, List<List<Byte>>>(fields)); //*
        } else {
            daBytes.add((K) new EnumMap<T, List<Byte>>(fields)); //*
        }
        for (T daField : fields.getEnumConstants()) {
            List<Byte> field = new ArrayList<Byte>();
            // populate "field"
            D map = (D) daBytes.get(currentEntry);
            if (hasLists) {
                List<List<Byte>> fieldEntries = new ArrayList<List<Byte>>();
                // populate "fieldEntries"
                ((EnumMap<T, List<List<Byte>>>) map).put(daField,
                    fieldEntries); //*
            } else {
                ((EnumMap<T, List<Byte>>) map).put(daField, field); //*
            }
        }
    }
    return (List<EnumMap<T, D>>) daBytes; //*
}

如果hasLists是假的,那么我需要 D 是一个List<Byte>else a List<List<Byte>>daList变量是List<EnumMap<T, D>>一个。现在(对我来说)定义似乎很自然:

List<EnumMap<T, D>> daBytes;

但是一旦我这样做并改变:

if (hasLists) {
    daBytes = (List<EnumMap<T, D>>) new ArrayList<EnumMap<T, List<List<Byte>>>>();
}

我收到一个错误:

不能从ArrayList<EnumMap<T,List<List<Byte>>>>List<EnumMap<T,D>>

一直在循环使 daBytes 成为对象,List<?>等等,但总是使用直接强制转换或导致警告的通用强制转换。必须有一种方法可以在没有强制转换的情况下干净地编译

4

1 回答 1

2

我做了一些重构,提取了其他海报所建议的“方法对象”。这是所谓的“策略类”设计模式的一个实例。

无论您在哪里检查,hasLists我都介绍了一种抽象方法。事实证明,您不再需要K类型参数。

该代码在顶部产生了一个未经检查的警告,我已在其中检查hasLists以选择抽象类的实现。

public static <X, T extends Enum<T> & Fields<?, ?, List<X>>>
List<EnumMap<T, List<X>>> getEntries(InputStream is, Class<T> fields) throws IOException {
    final List<List<Byte>> entries = new ArrayList<List<Byte>>();
    // populate "entries"

    FieldsStrategy<X, T> strategy = selectStrategy(fields);
    return strategy.getEntries(entries);
}

private static <X, T extends Enum<T> & Fields<?, ?, List<X>>>
FieldsStrategy<X, T> selectStrategy(Class<T> fields) {
    final boolean hasLists = hasLists(fields);
    return hasLists
            ? (FieldsStrategy<X, T>) new ByteListFieldsStrategy(fields) //* this is the only unchecked warning
            : (FieldsStrategy<X, T>) new ByteFieldsStrategy(fields);    //* this is the only unchecked warning
}

private abstract static class FieldsStrategy<X, T extends Enum<T> & Fields<?, ?, List<X>>> {
    private Class<T> fields;

    public FieldsStrategy(Class<T> fields) {
        this.fields = fields;
    }

    public List<EnumMap<T, List<X>>> getEntries(List<List<Byte>> entries) {

        List<EnumMap<T, List<X>>> daBytes = new ArrayList<EnumMap<T, List<X>>>();
        final int numOfEntries = entries.size();
        for (int currentEntry = 0; currentEntry < numOfEntries; ++currentEntry) {
            // add an element in daBytes for this currentEntry
            daBytes.add(new EnumMap<T, List<X>>(fields));
            for (T daField : fields.getEnumConstants()) {
                EnumMap<T, List<X>> map = daBytes.get(currentEntry);
                map.put(daField, getFieldData(daField));
            }
        }
        return daBytes;
    }

    protected abstract List<X> getFieldData(T daField);

}

public static class ByteFieldsStrategy<T extends Enum<T> & Fields<?, ?, List<Byte>>>
        extends FieldsStrategy<Byte, T> {
    public ByteFieldsStrategy(Class<T> fields) {
        super(fields);
    }

    protected List<Byte> getFieldData(T daField) {
        ArrayList<Byte> field = new ArrayList<Byte>();
        // populate "field"
        return field;
    }
}

public static class ByteListFieldsStrategy<T extends Enum<T> & Fields<?, ?, List<List<Byte>>>>
        extends FieldsStrategy<List<Byte>, T> {
    public ByteListFieldsStrategy(Class<T> fields) {
        super(fields);
    }

    protected List<List<Byte>> getFieldData(T daField) {
        List<List<Byte>> fieldEntries = new ArrayList<List<Byte>>();
        // populate "fieldEntries"
        return fieldEntries;
    }
}

您可能可以通过移动hasLists()逻辑和开关来删除唯一剩余的未检查警告,以选择使用哪个策略类到Fields接口并在enum类中实现它。

更新:这里是更新的定义selectStrategy并且不会Fields引发任何警告:

public static interface Fields<T extends Enum<T> & Fields<T, D, K>, D extends Data, K> {
    // ....

    GetEntries<K, T> selectStrategy();
}

private static <K, T extends Enum<T> & Fields<T, ?, K>>
GetEntries<K, T> selectStrategy(Class<T> fields) {
    for (T field : fields.getEnumConstants()) {
        return field.selectStrategy();
    }
    throw new IllegalArgumentException("Enum type has no instances: " + fields);
}

您需要selectStrategy()在您的enum类型中实现并返回适当的GetByteEntriesGetByteListEntries.

您现在可以删除hasLists()

于 2013-09-12T09:30:07.693 回答