Search code examples
javagenericscastingtype-safety

Casting to List<SomeType> issues an unchecked cast warning while casting to SomeType does not


Why does this:

public <T> List<byte[]> getData(T data) {
    Location loc = (Location) data;
    // ...
}

not generate any warnings, while this:

public <T> List<byte[]> getData(T data) {
    List<ScanResult> scanRes = (List<ScanResult>) data;
    // ...
}

generates Type safety: Unchecked cast from T to List<ScanResult>?

How can I resolve the warning?
As a design is this kind of method declaration a smell?

public <T> List<byte[]> getData(T data)

is an interface method implemented in different classes with different data types - the first line of all implementations is such a cast


Solution

  • You get the warning because the cast (List<ScanResult>) data is not safe. Due to type erasure, List<ScanResult> will be List during runtime, so there will be no real type check regarding the element type of the list. That is, that cast will succeed even if you get List<String> as a parameter and later you will get a ClassCastException when you try to access the list:

    ScanResult result = data.get(0); // ClassCastException: String
    

    One way to avoid it is making the interface generic:

    public interface DataProvider<T> {
        public List<byte[]> getData(T data);
    }
    

    And then define the specific type argument at implementations:

    public class DataProviderFromLocation implements DataProvider<Location> {
        public List<byte[]> getData(Location data) {
        }
    }
    
    public class DataProviderFromScanResultList implements DataProvider<List<ScanResult>> {
        public List<byte[]> getData(List<ScanResult> data) {
        }
    }
    

    I don't know if it is suitable for your needs.