public static void
public static void

Reputation: 1193

Is this abuse of casting?

I have a list of some object

List<MyObject>

But I know it to be a list of some object that inherits from MyObject

List<ChildObject>

Trying to cast from one to the other gives me an "Unconvertible Types" warning. However, if I first cast to object and then cast to a list cast to the second type then the warning goes away

List<ChildObject> myChildList = (List<ChildObject>) (Object) myObjectList

This seems to work fine. Is there any reason I shouldn't be doing this? Could it throw an error, is there a better way or is it considered bad practice?

Upvotes: 3

Views: 141

Answers (5)

akhil_mittal
akhil_mittal

Reputation: 24157

Generics were primarily designed for safe type checking at compile time. And they should not really be mixed with casting as casting pospones this type-safety check to runtime. Consider the following example where Vehicle is a base class extended by various classes: Bike, Car etc.

List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(new Bike("Yamaha"));
vehicles.add(new Car("VW"));
vehicles.add(new Car("BMW"));

List<Car> cars = (List<Car>)(Object)vehicles;
for (Car vehicle : cars) {
      System.out.println(vehicle.getType());
}

Here I am only iterating over List<Car> but you can see that this program can lead to fatal errors as the first item is not a Car but a Bike.

Upvotes: 0

Malt
Malt

Reputation: 30285

The problem is that while MyObject and ChildObject are related, List<MyObject> and List<ChildObject> are not, that's why you get the error.

Your casting solution works, but it throws type safety out the window, which can lead to bugs. The correct way of doing the transition from List<MyObject> to List<ChildObject> is to define the list with a wildcard:

    //From Child to parent
    List<? extends ChildObject> child1 = new ArrayList<>();
    List<? extends MyObject> parent1 = child1;

    //From parent to child
    List<? extends MyObject> parent2 = new ArrayList<>();
    List<? extends ChildObject> child2 = (List<? extends ChildObject>) parent2;

You can read more about it in this Java tutorial.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

Is there any reason I shouldn't be doing this?

Generic type parameter on the list is there to help compiler do type checking for you at compile time. Casting throws away this check, moving the check to run time.

Could it throw an error?

Yes, it could, if the list contains objects other than ChildObject. The worst part is that the cast could fail in some entirely unrelated place, where your code has no cast at all.

For example, if you do this

// Do the hack; 
List<ChildObject> myChildList = (List<ChildObject>) (Object) myObjectList;
...
// Iterate over your list
for (ChildObject c : myChildList) {
    ...
}

In the example above, if myObjectList has some classes other than ChildObject, there would be a class cast exception at runtime. However, it would happen in the header of the for loop, not at the point where you have your cast.

Is there a better way, or is it considered bad practice?

A better way would be creating a collection of ChildObjects, and populating it with the content of the original array.

Upvotes: 3

Alexander
Alexander

Reputation: 48252

Return List<? extends MyObject> where you are returning List<MyObject> now. This would provide for avoiding typecasts

Upvotes: 3

OldCurmudgeon
OldCurmudgeon

Reputation: 65813

If you could do what you want to do without casting then this is an abuse of casting. If the result of your casting causes a run-time error then this is an abuse of casting.

Since generics was added to Java, casting is mostly unnecessary - casting should be kept to a minimum because it hides errors that could be found at compile time until run time.

Upvotes: 0

Related Questions