如何在运行时解析泛型变量时避免未经检查的强制转换?

时间:2022-06-28 16:04:27

I have a parametrized value, that is resolved at runtime:

我有一个参数化值,在运行时解决:

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;
        }
    }
}

Is there a way to avoid unchecked cast in the code above (marked with a long comment)?

有没有办法在上面的代码中避免未经检查的强制转换(标有长注释)?

4 个解决方案

#1


6  

Generally, no way, since type parameter is bound to declaration. And what you want to do is to change static declaration based on the runtime value.

一般情况下,没办法,因为类型参数绑定到声明。您要做的是根据运行时值更改静态声明。

However, you can minimize area of unchecked cast by declaring parameterized method that adds type parameter

但是,您可以通过声明添加类型参数的参数化方法来最小化未选中的强制转换区域

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

and then use

然后使用

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

#2


3  

Maybe. Instead of dumb String tags, you can use a type which encodes the type information. See this blog post: http://blog.pdark.de/2010/05/28/type-safe-object-map/

也许。您可以使用对类型信息进行编码的类型,而不是哑字符串标记。请参阅此博客文章: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;
    }
}

plus changing the constructor of Field to public Field(FieldKey<T> key, T value).

加上将Field的构造函数更改为public Field(FieldKey 键,T值)。

You still have to cast but compile time checks will make sure that they never fail.

您仍然必须进行转换,但编译时间检查将确保它们永远不会失败。

#3


2  

You can use the annotation to do so. Use below annotation:

您可以使用注释来执行此操作。使用以下注释:

@SuppressWarnings("unchecked")

#4


1  

All the answers are fine, but I think there is not enough emphasis on why you're getting a warning and are casting.

所有的答案都很好,但我认为没有足够强调为什么你会收到警告并且正在施展。

You are explicitly circumventing the type system by performing an unchecked cast. By saying "I have information about this type that is not available to the compiler" - you are telling the compiler you know better.

您通过执行未经检查的强制转换明确规避了类型系统。通过说“我有关于此类型的信息,编译器无法使用” - 您告诉编译器您更了解。

That is of course a possible and reasonable use case: otherwise these casts would not be allowed, but a warning is good since it indicates you should be really sure what the type is.

这当然是一个可能和合理的用例:否则这些强制转换是不允许的,但是警告是好的,因为它表明你应该确定类型是什么。

This makes perfect sense. In fact, if you check libraries like GSON that do serialization they are full of these warnings and supressions.

这很有道理。事实上,如果您检查像GSON这样的序列化库,那么它们就会充满这些警告和压抑。

Don't worry about your code - it's all fine. If there was a way to "trick" the compiler to not emit the warning that would have been a serious problem on the other hand :)

不要担心你的代码 - 一切都很好。如果有一种方法可以“欺骗”编译器不发出本来会出现严重问题的警告:)

#1


6  

Generally, no way, since type parameter is bound to declaration. And what you want to do is to change static declaration based on the runtime value.

一般情况下,没办法,因为类型参数绑定到声明。您要做的是根据运行时值更改静态声明。

However, you can minimize area of unchecked cast by declaring parameterized method that adds type parameter

但是,您可以通过声明添加类型参数的参数化方法来最小化未选中的强制转换区域

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

and then use

然后使用

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

#2


3  

Maybe. Instead of dumb String tags, you can use a type which encodes the type information. See this blog post: http://blog.pdark.de/2010/05/28/type-safe-object-map/

也许。您可以使用对类型信息进行编码的类型,而不是哑字符串标记。请参阅此博客文章: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;
    }
}

plus changing the constructor of Field to public Field(FieldKey<T> key, T value).

加上将Field的构造函数更改为public Field(FieldKey 键,T值)。

You still have to cast but compile time checks will make sure that they never fail.

您仍然必须进行转换,但编译时间检查将确保它们永远不会失败。

#3


2  

You can use the annotation to do so. Use below annotation:

您可以使用注释来执行此操作。使用以下注释:

@SuppressWarnings("unchecked")

#4


1  

All the answers are fine, but I think there is not enough emphasis on why you're getting a warning and are casting.

所有的答案都很好,但我认为没有足够强调为什么你会收到警告并且正在施展。

You are explicitly circumventing the type system by performing an unchecked cast. By saying "I have information about this type that is not available to the compiler" - you are telling the compiler you know better.

您通过执行未经检查的强制转换明确规避了类型系统。通过说“我有关于此类型的信息,编译器无法使用” - 您告诉编译器您更了解。

That is of course a possible and reasonable use case: otherwise these casts would not be allowed, but a warning is good since it indicates you should be really sure what the type is.

这当然是一个可能和合理的用例:否则这些强制转换是不允许的,但是警告是好的,因为它表明你应该确定类型是什么。

This makes perfect sense. In fact, if you check libraries like GSON that do serialization they are full of these warnings and supressions.

这很有道理。事实上,如果您检查像GSON这样的序列化库,那么它们就会充满这些警告和压抑。

Don't worry about your code - it's all fine. If there was a way to "trick" the compiler to not emit the warning that would have been a serious problem on the other hand :)

不要担心你的代码 - 一切都很好。如果有一种方法可以“欺骗”编译器不发出本来会出现严重问题的警告:)