Подтвердить что ты не робот

Как избежать неконтролируемого приведения, когда универсальная переменная разрешена во время выполнения?

У меня есть параметризованное значение, которое разрешено во время выполнения:

public class GenericsMain {
    public static void main(String... args) {
        final String tag = "INT";

        Field field = resolve(tag);

        if (tag.equals("INT")) {
            /*
                In here I am using the "secret knowledge" that if tag equals INT, then
                field could be casted to Field<Integer>. But at the same time I see an unchecked cast
                warning at here.

                Is there a way to refactor the code to be warning-free?
             */
            Field<Integer> integerField = (Field<Integer>) field;

            foo(integerField);
        }
    }

    public static Field resolve(String tag) {
        switch (tag) {
            case "INT":
                return new Field<>(1);
            case "DOUBLE":
                return new Field<>(1.0d);
            default:
                return null;
        }
    }

    public static <T> void foo(Field<T> param) {
        System.out.println(param.value);
    }

    static class Field<T> {
        public final T value;

        public Field(T value) {
            this.value = value;
        }
    }
}

Есть ли способ избежать неконтролируемого приведения в коде выше (помечен длинным комментарием)?

4b9b3361

Ответ 1

Как правило, никоим образом, поскольку параметр типа привязан к объявлению. И вы хотите изменить статическое объявление на основе значения времени выполнения.

Тем не менее, вы можете свести к минимуму область неконтролируемого приведения, объявив параметризованный метод, который добавляет параметр типа

@SuppressWarnings("unchecked")
private static <T> Field<T> asParameterized(Field<?> field) {
    return (Field<T>) field;
}

а затем используйте

Field<Integer> intField = GenericsMain.<Integer> asParameterized(field);

Ответ 2

Может быть. Вместо немых тегов String вы можете использовать тип, который кодирует информацию о типе. Смотрите это сообщение в блоге: http://blog.pdark.de/2010/05/28/type-safe-object-map/

public class FieldKey<T> {
    private String name;

    public FieldKey(String name) {
        this.name = name;
    }

    public String name() {
        return name;
    }
}

плюс изменение конструктора от Field до public Field(FieldKey<T> key, T value).

Вам все равно придется выполнять кастинг, но компиляция проверок времени гарантирует, что они никогда не сбой.

Ответ 3

Вы можете использовать аннотацию для этого. Используйте ниже аннотацию:

@SuppressWarnings("unchecked")

Ответ 4

Все ответы в порядке, но я думаю, что недостаточно внимания уделяется тому, почему вы получаете предупреждение и кастинг.

Вы явно обходите систему типов, выполняя непроверенный бросок. Говоря "У меня есть информация об этом типе, недоступном компилятору" - вы говорите компилятору, которого знаете лучше.

Это, конечно, возможный и разумный случай использования: в противном случае эти отбрасывания не будут разрешены, но предупреждение хорошее, поскольку оно указывает, что вы действительно должны знать, что такое тип.

Это имеет смысл. Фактически, если вы проверяете библиотеки, такие как GSON, которые выполняют сериализацию, они полны этих предупреждений и подавлений.

Не беспокойтесь о своем коде - все в порядке. Если бы был способ "обмануть" компилятор, чтобы не выдавать предупреждение, которое было бы серьезной проблемой, с другой стороны:)