Java:如何编写方法来接受子而不转换为父级?

时间:2009-12-17 07:20:34

标签: java casting parent class-hierarchy

不确定如何标题...

所以我有三个Event子类:WeightEventTimedEventRepEvent。通过任何方式,我得到一个孩子的对象。现在我想将该子事件发送到另一个对象中的方法,以便它可以使用getSavedEvents()方法从中提取数据。该方法仅存在于子项中,因为提取数据特定于事件类型。

我从

开始
public void setEvent(Event e) {

但是将我的子对象强制转换为Event(父)对象。

有没有办法解决这三种不同方法的问题。一个孩子一个人?

public void setEvent(WeightEvent e) {
public void setEvent(TimedEvent e) {
public void setEvent(RepEvent e) {

感谢您的任何建议。

-John

8 个答案:

答案 0 :(得分:7)

即使引用是强制转换的,它也不会更改实际对象的类型。当您传递引用时,它仍将是对子对象的实例的引用。通常这是足够的,如果需要,在父类型中使用适当的抽象方法。

但是,如果您想要的方法特定于子类型,并且您无法提出适当的抽象,而且所有这些抽象都可以通用,那么您必须使用instanceof在您的setEvent代码中或必须重载您的方法...因为您将不得不根据事件的确切类型调用不同的代码位。

这有点模糊,因为除了几个方法签名之外我们看不到任何代码。如果您可以向我们提供有关您正在尝试做什么的更多详细信息,特别是在setEvent需要实现的内容以及子类中的不同方法方面,我们可以提供更多帮助。

答案 1 :(得分:3)

不应该打开类型,而应该为每种类型的事件类型定义不同的事件调用方法。这称为Template method pattern。 (它与C ++模板无关,BTW)

使用此模式,您的EventTable类将变为如下所示:

public class EventTable {
  public void setEvent(Event e) {
    int x = 0;
    columns = e.getFields();
    Event[] savedEvents = e.getSavedEvents();
    for(Event ev : savedEvents) {
      tempdata[x] = ev.getTempData();
      x++;
    }
  }
}

请注意,整个开关已被替换为对getTempData()的单次调用。这个方法在Event中是抽象的,就像getSavedEvents:

一样
public abstract class Event {
  public Date getDate() { return(_date); }
  public abstract Event[] getSavedEvents();
  public abstract int[] getTempData();
  public int[] getFormattedDate() {
    ...

}

然后在每个子类中定义getTempData()方法。例如:

public class WeightEvent extends Event {
  public int getWeight() { return(_weight); }
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getWeight(),
      getReps()
    };
  }
}

public class TimedEvent extends Event {
  public String getTimeInHMS() { return(_timeString); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getTimeInHMS()
    };
  }
}

public class RepEvent extends Event {
  public int getReps() { return(_reps); }
  public int[] getTempData() {
    return new int[]{
      getFormattedDate()[0],
      getReps()
    };
  }
}

答案 2 :(得分:1)

您可以使用泛型来执行此操作。

按如下方式定义Event类:

public abstract class Event<T extends Event> {
    public abstract void setEvent(T e);
}

这定义了一个期望用任何扩展Event的类型创建的类。

然后在您的子类中使用子类作为泛型类型实现类似的东西:

class WeightEvent extends Event<WeightEvent>
{

    @Override
    public void setEvent(WeightEvent e) {
        ...
    }

}

答案 3 :(得分:1)

我认为你的probem在拥有getSavedEvents()变量时正在调用Event 如果是这样,请向getSavedEvents()添加一个抽象的Event方法,该方法也必须声明为abstract:

    public abstract class Event {
        public abstract Events getSavedEvents();
        ...
    }

因为Event是抽象的,所以你无法创建它的实例;它必须是子类才能使用。如果这是一个问题,请在Event.getSavedEvents()中抛出一个Exception或对你的应用程序做任何合理的事情(一无所有,只返回null):

    public class Event {
        public Events getSavedEvents() {
            throw new UnsupportedOperationException("must be called in a child class");
            // OR return null;
        ...
    }

现在您可以在其他对象中调用getSavedEvents()方法:

    public class OtherObject {
        private Event event;
        public void setEvent(Event e) {
            event = e;
            ...
            Events events = event.getSavesEvents();

将使用由e的真实类实现的方法,例如如果eTimedEvent,则会调用该类中的方法。

答案 4 :(得分:0)

您可以将Event e对象强制转换为子类 - 我认为Java中的instanceof运算符可以帮助您。

答案 5 :(得分:0)

您可以在界面后面抽象问题

interface IEvent
{
    abstract public void doSomething();
}

然后让你所有的事件类都实现它,例如

class WeightedEvent implements IEvent
{
    public void doSomething()
    {
        // do something
    }
}

然后您只需要一个方法,不需要进行任何类型检查

public void setEvent(IEvent e)
{
    e.doSomething();
}

HTH

答案 6 :(得分:0)

可以使用Visitor pattern

答案 7 :(得分:0)

使用abstract帮助getSavedEvents()方法,因为所有子项都实现了该方法。

这是setEvent()的代码:

public class EventTable {
public void setEvent(Event e) {
 int x = 0;
 int type = e.getEventType();

 columns = e.getFields();
 Event[] savedEvents = e.getSavedEvents();
 for(Event ev : savedEvents) {
  tempdata[x][0] = ev.getFormattedDate()[0];
  switch(type) {
   case EVENTTYPE.WEIGHT:
    tempdata[x][1] = ev.getWeight();
    tempdata[x][2] = ev.getReps();
   break;
   case EVENTTYPE.TIMED:
    tempdata[x][1] = ev.getTimeInHMS();
   break;
   case EVENTTYPE.REP:
    tempdata[x][1] = ev.getReps();
   break;
  }
  x++;
 }
}
}

在我将“abstract”添加到Event类并定义了一个名为getSavedEvents()的抽象方法之后,此代码可以正常工作。

下一个问题是getWeight(),getReps()和getTimeInHMS()方法。它们特定于子事件的类型,并且在父事件类中也不存在。如果我在Event中将它们变为抽象,那么现在我必须在每个子节点中定义它们,即使getReps()没有TimedEvent的上下文。

public class Event {
 public Date getDate() { return(_date); }
}
public class WeightEvent extends Event {
 public int getWeight() { return(_weight); }
 public int getReps() { return(_reps); }
}
public class TimedEvent extends Event {
 public String getTimeInHMS() { return(_timeString); }
}
public class RepEvent extends Event {
 public int getReps() { return(_reps); }
}

显然是缩写代码。 WeightEvents具有与之关联的日期,重量和代表。 TimedEvents具有与之关联的日期和时间长度。 RepEvents具有与之关联的日期和代表数。日期方法都在父级中,因为它们在事件中是通用的。

如果我没有生成getWeight(),getReps()是抽象的,只在它们相关的子节点声明它们,这是我在上面复制的setEvent()方法中从EventTable得到的错误:

EventTable.java:124: cannot find symbol
symbol  : method getWeight()
location: class Event
     tempdata[x][1] = ev.getWeight();

-John