从超级对象列表中向下转换

时间:2018-07-29 18:20:23

标签: java arraylist downcast

我正在编写一个跟踪一个人拥有多少资产的程序。每个人类都有一个称为Value_Item对象的ArrayList。

Value_Item是一个简单的对象。

class Value_Item
{ float _value;
  String _currency;
  String _type //+getters and setters}

如果不愿意澄清任何内容,我认为上面的代码是不言自明的。

我从Value_Item扩展到几个类别,例如股票,基金,现金等。 所有这些都有其不同的属性,例如权益“单价”。

我当前存储信息的解决方案是创建一个子类,当我调用超类构造函数设置子类的类型时,当我需要对数据采取行动时,比如说获取所有持有资金的单价,我检查类型和垂头丧气。

例如

if(_value_item.getType()=="FUND){
Fund fund = (Fund) _value_item 
float unit_price = fund.getUnitPrice()}

但是我读到,向下转换是不受欢迎的,并且解决方案本身并不十分优雅,是否有更好的方法来实现java等效的“ pythonic”。

1 个答案:

答案 0 :(得分:2)

  

不过,我读到偏爱偏向

的确。它只能用作最后的手段。本质上是因为检查对象的类型以执行处理是不可维护的,并且在编译时它还会产生不太安全的代码,因为检查类型只会在运行时发生。

  

有没有更好的方法来执行此Java等效操作?   “ pythonic”。

在您的情况下,主要问题是Value_Item代表的概念太宽泛,就像您定义类ValueForAnyThing一样。
很难使用List<ValueForAnyThing>的元素而不会降低。

即使不是主要的子类,也可能有助于防止重复代码,但是当您希望以统一的方式使用子类的对象但子类太宽泛时,子类也可能显得无助。

对于声明为元素类型为通用基本类型的集合/数组,防止向下转换的两种已知方法是:

1)在基类方法中移动行为。
2)不在同一集合/数组中收集所有子类实例。


1)在基类方法中移动行为。

假设以下摘录构成了所有子类都可以进行的计算的一部分,但是每个子类都有自己的字段/方法:

if(_value_item.getType()=="FUND){
  Fund fund = (Fund) _value_item 
  float unit_price = fund.getUnitPrice()}
}

您可以在compute()中引入抽象的ValueItem方法:

public class ValueItem{
    public abstract float compute();
    // ...
}

子类将实现它:

public class Cash extends ValueItem{
    @Override
    public float compute(){
       // ...
    }
    // ...
}

public class Equity extends ValueItem{
    @Override
    public float compute(){
       // ...
    }
    // ...
}

现在您可以在compute()的任何元素(或全部)上调用List方法:

for (ValueItem valueItem : valueItems){
     float computation = valueItem.compute();
     // ....
}

2)不在同一集合/数组中收集所有子类实例。

您确实可以将List分成多个部分,以将应统一处理的内容组合在一起。

还请注意,如果可以统一操纵多种项目,则可以引入它们共有的界面。
例如,假设EquityFund可以被统一操纵,因为它们属于相同的特定概念:UnitPricable并假设Cash是一个具有自己方式的特定概念要表示/操作,您可以这样获得:

public class Cash extends ValueItem{
   ...
}

public class Equity extends ValueItem implements UnitPricable{
   ...
}

public class Fund extends ValueItem implements UnitPricable{
   ...
}


public class Person{
   private List<Cash> cashes = new ArrayList<>();
   // the next one groups two kind of subclasses
   private List<UnitPricable> unitPricables = new ArrayList<>();
   ....

   // operations that works on the Cash subclass instances
   public void computeCashes(){
     for (Cash cash : cashes){
        ... = cash.getSpecificCashField();               
        ... = cash.specificCashMethod();               
        ...
     }
   }

   // operations that work on multiple subclasses instances : Fund and Entity
   public void computeUnitPricables(){
     for (UnitPricable up: unitPricables){
        ... = up.getUnitPrice();               
        ... = up.specificUnitPriceMethod();               
        ...
     }
   }
}