如何在运行时识别对象的类型?

时间:2012-03-22 13:55:30

标签: java oop design-patterns

类:

public abstract class BaseHolidayPackageVariant {
    private Integer variantId;
    private HolidayPackage holidayPackage;
    private String holidayPackageType;
}

public class LandHolidayPackageVariant extends BaseHolidayPackageVariant{

}

public class FlightHolidayPackageVariant extends BaseHolidayPackageVariant{
    private Destination originCity;
}

public class HolidayPackage{
    ArrayList<BaseHolidayPackageVariant> variants;

    BaseHolidayPackageVariant defaultVariant;
}

在运行时,如何知道变体[]中的给定对象是否为LandPackageVariantFlightPackageVariant类型,而不执行以下任何操作:

if(holidayPackageType.equals("LandHolidayPackageVariant")
 obj = (LandHolidayPackageVariant)variant[i];
else if(holidayPackageType.equals("FlightHolidayPackageVariant")
 obj = (FlightHolidayPackageVariant)variant[i];

这个问题源于我问here

的设计问题

7 个答案:

答案 0 :(得分:5)

在良好的面向对象设计中,您不应该知道对象是否属于特定类型。你只需在它上面调用方法,对象就是正确的。

例如,FlightHolidayPackageVariant的字段originCity不在其他HolidayPackageVariant类中,您希望在UI中呈现该字段。解决这个问题的面向对象的方法是让HolidayPackageVariant以某种方式负责控制自己的渲染。假设您的UI将显示每个变体的属性列表。您可以让变体提供这些列表:

public abstract class BaseHolidayPackageVariant {
    private int cost;

    public Map<String, String> getDetails() {
        HashMap<String, String> details = new HashMap<String, String>();
        details.put("cost", String.format("%.2f", cost / 100.0));
        return details;
    }
}

public class FlightHolidayPackageVariant extends BaseHolidayPackageVariant {
    private Destination originCity;

    @Override
    public Map<String, String> getDetails() {
        Map<String, String> details = super.getDetails();
        details.put("origin city", originCity.getName());
        return details;
    }
}

现在,您的UI代码可以简单地询问每个变体对象的详细信息,而无需知道它是什么类型的变体。

答案 1 :(得分:3)

试试这个:

if (variant[i] instanceof LandHolidayPackageVariant) {
    LandHolidayPackageVariant obj = (LandHolidayPackageVariant)variant[i];
    // do stuff
}
else if (variant[i] instanceof FlightHolidayPackageVariant) {
    FlightHolidayPackageVariant obj = (FlightHolidayPackageVariant)variant[i];
    // do other stuff
}

请注意,如果您还有从这些类型之一派生的类型,则应检查 first ,因为对于该情况,上面的检查也将返回true。

更好的方法可能是让派生类通过定义要在基类上重写的适当方法来实现所需的特定逻辑。这样您就不需要检查类型并可以充分利用多态性。

答案 2 :(得分:1)

像这样:

if(object instanceof LandPackageVariant) {
    System.out.println("it's a LandPackageVariant");
}

答案 3 :(得分:1)

if(holidayPackageType.equals("LandHolidayPackageVariant")
 obj = (LandHolidayPackageVariant)variant[i];
else if(holidayPackageType.equals("FlightHolidayPackageVariant")
 obj = (FlightHolidayPackageVariant)variant[i];

这样做obj必须是BaseHolidayPackageVariant,所以你甚至不需要投射也不需要if这件事。

如果您希望具有特定类Land或Flight的对象调用特定方法,那么您可能应该检查对象模型。

答案 4 :(得分:0)

您可以使用instanceof。

例如: {

enter code here
if (variant[i] instanceof LandHolidayPackageVariant) {
  //do something
} else if(variant[i] instanceof FlightHolidayPackageVariant){
  //do something
}

}

看看:http://www.java2s.com/Tutorial/Java/0060__Operators/TheinstanceofKeyword.htm

更好的选择是设计程序,以便不需要instanceof运算符。

答案 5 :(得分:0)

您可以使用instanceof运算符:

if (variant[i] instanceof LandHolidayPackageVariant)
    obj = (LandHolidayPackageVariant) variant[i];

但是,通常你不应该需要它。使用instanceof来区分类的原因很少,但通常子类本身应该通过它们的公共超类接口提供所需的不同功能。

答案 6 :(得分:0)

是的,这里的答案都是 - 矛盾的 - 对。

汤姆回答说你的问题是可疑的是球。通常没有理由从其层次结构中的其他人确定对象的特定类型。 (我的意思是除了花哨的反思之外)

Botz3000的答案(就像我输入的所有其他产品一样)在技术上是正确的。

猜测,你正在研究在课堂上调用哪种方法?在这种情况下,使用@Override注释,在子类中重新定义方法,并在父类中提供一个抽象方法(或者是基于事物的具体版本?)

从你的班级名称来看,我怀疑你应该对抽象工厂模式和(非常简单的)策略模式进行快速分解。

PS如果你想获得花哨并使用反射,你可以调用getClass()并检查它。但是有,并且我想强调这一点,没有理由这样做,这是不好的做法。但是你在那里。