javaarraylistcastingcompiler-warningsunchecked-cast

How to address unchecked cast Object to ArrayList<Vehicle>


For a class I was assigned to write code to read objects of the class Vehicle using ObjectInputStream (in). The objects are stored in an ArrayList called orders.

SSCE:

// Read all orders
Object obj = in.readObject();
orders = (ArrayList<Vehicle>) obj;

However, the compiler complains:

MacBook:Homework Brienna$ javac Orders.java -Xlint:unchecked
Orders.java:152: warning: [unchecked] unchecked cast
                    orders = (ArrayList<Vehicle>) in.readObject();
                                                                ^
  required: ArrayList<Vehicle>
  found:    Object
1 warning

I always try to improve my code instead of ignoring or suppressing warnings. In this case, I have come up with a solution, but I'm trying to understand why it works, and if there is a better solution.

This update stops the warning:

// Read all orders, casting each order individually
Object obj = in.readObject();
ArrayList ar = (ArrayList) obj;
for (Object x : ar) {
    orders.add((Vehicle) x);
}

Based on what I understand from what I've been reading, it works because (ArrayList<Vehicle>) obj may throw an exception if not all the elements are Vehicle. I am confused -- non-Vehicle objects can be added to the ArrayList even if its type parameter has been specified as Vehicle? Also, is there a better solution, e.g. using instanceof?


Solution

  • You were close. It is always safe to cast to ArrayList<?>:

    Object obj = in.readObject();
    ArrayList<?> ar = (ArrayList<?>) obj;
    
    orders.clear();
    for (Object x : ar) {
        orders.add((Vehicle) x);
    }
    

    You might even want to be extra safe and cast to something more generalized, like Iterable:

    Object obj = in.readObject();
    Iterable<?> ar = (Iterable<?>) obj;
    
    orders = new ArrayList<>();
    for (Object x : ar) {
        orders.add((Vehicle) x);
    }
    

    If you have control over the objects which were originally serialized, there is a way to avoid the loop entirely: Use an array instead of a Collection. Array types are always a safe cast (if they don’t have a generic type themselves):

    Object obj = in.readObject();
    orders = new ArrayList<>(Arrays.asList((Vehicle[]) obj));