实例和类型铸造技术

时间:2009-07-16 13:30:38

标签: java casting subclassing instanceof

我对技术和实施有疑问,而不是要解决的实际问题。最近我创建了一个抽象类,我们称之为A,它定义了它的子类的常见行为。

我用它来构造几个子类B,C和D,然后传递给超类 - 子类结构之外的其他方法,它接受一个类型A(因此能够处理所有B,C和D)。

在Java中,我使用instanceof来检索真正的类型,但是我最终不得不对真实类型进行大量的转换,而且它看起来像一团糟。有没有人对如何使代码更清洁有任何建议?

我尝试过的一种方法是从超类的参数重构子类类型的实例,这样我就可以用它的实际类型处理对象,从而避免了类型转换。由于这些子类中的每一个都是单例(是的,它们保持状态),我觉得这样做很好。这看起来像是一件糟糕的事吗?

感谢所有回答的人,非常感谢!

编辑:我在斜体字中添加了进一步的说明。感谢。

4 个答案:

答案 0 :(得分:3)

泛型是为了解决这个问题。

考虑以下示例:

public class SuperClass<T extends SuperClass> {

     public abstract void someMethod(T param);

}


public class SubClassA extends SuperClass<SubClassA> {

    public void someMethod(SubClassA param) {}
}
编辑:鉴于评论,我会说那是一种设计气味。整个其他类要么需要子类来关联(此时可以应用相同的技术),或者涉及其他一些设计问题。在一个类上有一个方法来获取不同类的超类,然后继续关注子类型是很奇怪的。

如果这是你需要的,你可以通过方法重载来完成这个。考虑:

  public void someMethod(SuperClass param) {
      if (param instanceof SubClassA) {
         someMethod((SubClassA) param);
      } else if (param instanceof SubClassB) {
         someMethod((SubClassB) param);
      }
  }

  public void someMethod(SubClassA param) {}

  public void someMethod(SubClassB param) {}

但是这并没有让你脱离陷阱。这取决于它们有多少以及如何在这里看一个更重要的解决方案是多么不稳定。

答案 1 :(得分:3)

如果您需要检查类型,我不明白为什么要让它们从基类继承。抽象类/接口A定义了B,C和D应该实现的一系列函数,然后采用A实例的函数应该只调用那些抽象函数。如果你需要调用一个只包含B的函数(因此不会被覆盖),那么你的函数应该采用B的实例而不是A.

或者我完全忽略了这一点?我今天早上没有咖啡因。

答案 2 :(得分:0)

听起来你想要访客模式。就个人而言,我不是一个忠实的粉丝,但它的工作原理如下:

class A { abstract void visit(MyVisitor visitor); }

这必须在每个子类中实现:

class B extends A { 
    public void visit(MyVisitor v) { v.visit(this); }
}

因此实际访问者使用重载如下:

interface MyVisitor {
   public void visit(B b);
   public void visit(C c);
}

现在,您可以实现访问者并针对您的A实例调用visit。然后将调用正确的回调方法:

A a = new B();
a.visit(this);

假设this实例实现了MyVisitor,这将导致visit(B)方法的回调

答案 3 :(得分:0)

正如Yishai所说,它看起来像是一种设计气味。如果你有一个修改你的方法行为的instanceof-s,你就会走错路。考虑将此行为移动到A类的继承者中。

除此之外,您还可以使用泛型来参数化A类。这是一个代码示例

abstract class A<T extends A>{
   abstract protected void someMethod(T value);
}

class B extends A<B>{
    protected void someMethod(B value) {
    }
}

class C extends A<C>{
    protected void someMethod(C value) {
    }
}