Cast to generic type (T) gives "unchecked cast" warning
Asked Answered
L

3

6

I got a small problem here regarding generics bounded type with lists. Please help out!

Model.java

public class Model {
}

ClassA.java

public class ClassA<T extends Model> {
    private List<T> models;

    public ClassA() {
        models.add((T) new Model());
    }
}

It gives me an unchecked cast from Model to T warning on this line:

models.add((T) new Model());

I understand I'm getting this warning because all I can safely cast from a sub class into a super class but not the other way round.

Is there any way to get over this problem or can I just safely supress the warning?

Linkoski answered 26/9, 2013 at 15:19 Comment(6)
The T can be subclass of Model. So you cannot cast Model to its subclass. What do you want to do?Maitund
why not models.add(new T());?Kei
Note that even though you can cast and add it, you will get a ClassCastException when you try to use the elements in the list as T type objects where T is a subclass of Model.Roughshod
@Kei new T() won't compile due to type erasure.Eudora
You're trying to do it backwards. It's not safe to ignore that warning. Imagine class B that extends Model. Then declare ClassA<B> (which is valid because B extends Model). Then try doing a case from your new Model to B. That will fail, because while B is a Model, a Model is not B.Icefall
If you want them to just always use Model, then you don't need Generics.Kei
M
12

You can't do what you're trying to do.

Since T is a subclass of Model:

  • every T is a Model
  • but not every Model is a T.

Specifically:

If you construct a new Model by calling new Model(), the instance is exactly a Model and not an instance of any subclass.

Where Subclass extends Superclass, you can never successfully do this:

(Subclass) new Superclass();

Because of this, you can not successfully cast a new Model to an instance of T.

The compiler will just give you a warning which you can either ignore or suppress, but you'll get a ClassCastException when you run your program and call the add() method.

Maquette answered 26/9, 2013 at 15:33 Comment(0)
R
2

Take this example

public static void main(String[] args) {
    ClassA<SubModel> models = new ClassA<>();
    for (SubModel model : models.getModels()){
        model.run(); // runtime ClassCastException
    }
}
public static class ClassA<T extends Model> {
    private List<T> models = new LinkedList<>();

    public ClassA() {
        models.add((T)new Model()); // compiles and warns
    }

    public List<T> getModels() {
        return models;
    }
}
public static class SubModel extends Model {
    public void run() {
        System.out.println(this);
    }
}
public static class Model {
}

The object you've added to models is of runtime type Model, which doesn't have a run() method.

When you eventually try to use the object as an object of type SubModel, you'll get a ClassCastException as I do in the main() method.

You really shouldn't do this, ie. add parent type objects to possible suptype type objects.

Roughshod answered 26/9, 2013 at 15:35 Comment(0)
B
-1

You need to initialize the list before adding elements in your constructor. I think you you might have copied only the relavant code snippet and thats why it was left out.

Also, I think the only way is to suppress warnings. More info only covariance, contravariance here : Covariance, Invariance and Contravariance explained in plain English?

Beveridge answered 26/9, 2013 at 15:28 Comment(1)
Suppressing the warning will only delay the inevitable ClassCastException. And it's true that the list needs to be newed, but that's nothing to do with the (T) cast.Eudora

© 2022 - 2024 — McMap. All rights reserved.