How to address unchecked cast Object to ArrayList<Vehicle>

5.4k Views Asked by At

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?

2

There are 2 best solutions below

2
On BEST ANSWER

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));
0
On

first code excerpt your cast with generic (ArrayList) second code excerpt your cast without generic. cast is a runtime check - java compiler does type erasure, and at runtime there's actually no difference between a List<Vehicle> and List<Car>