Java: Работа с универсальными элементами и картами без приведения / @SuppressWarnings

Теперь я сталкивался с этой проблемой несколько раз и всегда решал ее с помощью @SuppressWarnings аннотаций.

Соответствующие интерфейсы / абстрактные классы:

public abstract class Data { }

public interface DataOperations {
    boolean isValid();
}

public interface DataOperationsFactory<T extends Data> {
    Class<T> getDataClass();
    DataOperations getOperations(T data);
}

Пример реализации:

public class DataImpl1 extends Data {
    public String foo;
}

public class DataImpl1Operations implements DataOperations {
    private DataImpl1 data;
    public DataImpl1Operations(DataImpl1 data) {
        this.data = data;
    }
    public boolean isValid() {
        return data.foo != null;
    }
}

public class DataImpl1OperationsFactory extends DataOperationsFactory<DataImpl1> {
    public Class<DataImpl1> getDataClass() {
        return DataImpl1.class;
    }
    DataOperations getOperations(DataImpl1 data) {
        return new DataImpl1Operations(data);
    }
}

Используя этот шаблон, я могу решить, нужно ли мне создавать new DataImpl1Operations каждый раз. Или, может быть, использовать final static NO_OP реализация или что у тебя.

Код:

Теперь я хотел бы поместить все эти заводы в Map<Class<T>, DataOperationsFactory<T>> (конструктор). А потом прочитайте из него (getOps метод).

public class Test {
    Map<Class<?>, DataOperationsFactory<?>> map;

    public Test(List<DataOperationsFactory<?>> fs) {
        for(DataOperationsFactory<?> f : fs) {
            map.put(f.getDataClass(), f);
        }
    }

    @SuppressWarnings("unchecked")
    public <T extends Data> DataOperations getOps(T data) {
        // --> Here I need to do an unchecked cast <--
        DataOperationsFactory<? super T> f =
                (DataOperationsFactory<? super T>) map.get(data.getClass());
        return f.getOperations(data);
    }
}

Есть ли способ сделать это без неконтролируемого кастинга?

1 ответ

Решение

Вы можете делегировать закрытому методу, который захватывает тип, так что его можно использовать для надежного приведения к правильному подклассу Data:

Map<Class<?>, DataOperationsFactory<?>> map;

// Unchanged
public Test(List<DataOperationsFactory<?>> fs) {
    for(DataOperationsFactory<?> f : fs) {
        map.put(f.getDataClass(), f);
    }
}

public DataOperations getOps(Data data) {
    DataOperationsFactory<?> f = map.get(data.getClass());
    return getOperations(f, data);
}

private static <T extends Data> DataOperations getOperations(DataOperationsFactory<T> f,
                                                             Data data) {
    return f.getOperations(f.getDataClass().cast(data));
}
Другие вопросы по тегам