简体   繁体   中英

Type Safety warning when casting to generic class in Java

I have a class

class Property<T> {
    value T;

    public void setValue(T value) {
        this.value = value;
    }
}

Now I have a list List<Property<?>> properties with various properties of various Types. I loop through this list and want to set the value of every Property. Therefore I need to cast the generic Property to the correct type like: eg for Integer:

if (property.getType().equals("Integer")) {
        Property<Integer> propInt = (Property<Integer>) property;
        propInt.setValue((Integer) values[i++]);
}

where values[] is an Object array which holds the values that I want to set.

Everything works fine, but Java complains about Type Safety "Unchecked cast from Property<?> to Property<Integer> ". A check like

if (property instanceof Property<Integer>){...}

is not possible though. How can I change my code to get rid of this warning, or do you know a better practice for my case?

The compiler complains because property is of type Property<?> which could or could not be of type Property<Integer> in general. This is an inherent limitation of the current java language due to type erasure.

In this particular case you are making sure that property is of class Property<Integer> by use of the getType method so it is safe to ignore the warning.

if (property.getType().equals("Integer")) {
        // we have made sure property is of class Property<Integer> so the cast is type safe
        @SuppressWarnings("unchecked")
        Property<Integer> propInt = (Property<Integer>) property;
        propInt.setValue((Integer) values[i++]);
}

It is important to document it with a comment otherwise a peer reviewing your code might not notice that indeed the cast is type safe and could confuse the warning supression as a malpractice.

The warning indicates, that at source level, the list may contain objects of any type () and you cast those to Integer, which would lead to a ClassCastException at runtime, in cases where the list contains a non-Integer object. So the warning indicates a potential problem at runtime.

You could get rid of the warning by either

  • declaring the List as List of Integers List<Integer>
  • or, suppress the warning using the @SuppressWarnings("unchecked") on the method or the list declaration.

If you can not guarantee, that the objects contained in the list are no Integer, then you should have the instanceof before the cast and the SuppressWarning. If you can guarantee it, then you should declare the list as list of Integers.

You can use annotation SuppressWarnings to ignore this warning:

@SuppressWarnings("unchecked") Property<Integer> propInt = (Property<Integer>) property;

but it's a risk to do this.

this warning is caused by type erasure , because when compile, generic type will be erased.

As you know generics in java suffer a bit from type erasure, all becomes Object at run-time.

As you test on strings like "Integer", it would seem adding a Class<T> could even be convenient.

class Property<T> {
    final Class<T> type;
    value T;

    public Property(Class<T> type) {
        this.type = type;
    }

    public void setAnyValue(Object value) {
        this.value = type.cast(value);
    }
}

Property<?> property = ...
//if (property.getType() == Integer.class) {
//    Property<Integer> propInt = (Property<Integer>) property;
//    propInt.setAnyValue((Integer) values[i++]);
//}
property.setAnyValue(values[i++]);

The usage of Object is due to the polymorph usage of Property instead of the more normal typing: your code mixes up differently typed properties and parallel values.

If you are using the spring framework, you can also use:

import static org.springframework.data.util.CastUtils.cast;
        Map<String,Object> messageMap = cast(exchange.getMessage().getBody());
        List<String> refIds = cast(messageMap.get("refIds"));

Note:

I wouldn't suggest using this unless the spring framework is already part of your application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM