这种滥用铸造?

时间:2015-09-04 10:10:34

标签: java casting

我有一些对象的列表

List<MyObject>

但我知道它是从MyObject继承的某个对象的列表

List<ChildObject>

尝试从一个投射到另一个给我一个“Unconvertible Types”警告。但是,如果我首先转换为object然后转换为转换为第二种类型的列表,那么警告就会消失

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

这似乎工作正常。我有什么理由不这样做吗?它会抛出一个错误,有更好的方法还是被认为是不好的做法?

5 个答案:

答案 0 :(得分:3)

现在返回List<? extends MyObject>返回List<MyObject>的地方。这将提供避免类型转换

答案 1 :(得分:3)

  

我有什么理由不这样做吗?

列表中的通用类型参数可以帮助编译器在编译时为您进行类型检查。施放抛弃了这张支票,将支票移动到运行时间。

  

会抛出错误吗?

是的,如果列表包含ChildObject以外的对象,则可以。最糟糕的是,演员阵容可能会在一些完全不相关的地方失败,你的代码根本没有演员阵容。

例如,如果你这样做

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

在上面的示例中,如果myObjectList有一些除ChildObject以外的类,则在运行时会出现类强制转换异常。但是,它会发生在for循环的标题中,而不是在你的演员阵容中。

  

有更好的方法,还是被认为是不好的做法?

更好的方法是创建一个ChildObject的集合,并用原始数组的内容填充它。

答案 2 :(得分:1)

问题是虽然MyObjectChildObject相关,但List<MyObject>List<ChildObject>不相关,这就是您收到错误的原因。

您的铸造解决方案有效,但它会将窗户的类型安全性抛出,这会导致错误。从List<MyObject>转换为List<ChildObject>的正确方法是使用通配符定义列表:

    //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;

您可以在this Java教程中阅读更多相关信息。

答案 3 :(得分:0)

如果你可以在没有施法的情况下做你想做的事,那么这就是滥用铸造。如果您的投射结果导致运行时错误,那么这就是滥用投射。

由于泛型被添加到Java中,因此大多数情况下都不需要进行转换 - 应该将转换保持在最低限度,因为它会隐藏在编译时可以在运行时发现的错误。

答案 4 :(得分:0)

泛型主要用于在编译时进行安全类型检查。并且它们不应该与铸造混合在一起,因为铸造会将此类型安全检查推迟到运行时。请考虑以下示例,其中Vehicle是由各种类扩展的基类:BikeCar等。

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());
}

此处我只是在List<Car>上进行迭代,但您可以看到此程序可能会导致致命错误,因为第一项不是Car而是Bike