java generics - cast to List<SomeType> issues unchecked cast warning while cast to SomeType not

Mr_and_Mrs_D picture Mr_and_Mrs_D · Sep 9, 2013 · Viewed 10.3k times · Source

Why this :

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

does 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 appease 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

Answer

Katona picture Katona · Sep 9, 2013

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.