【问题标题】:Instanceof and Type-casting TechniquesInstanceof 和类型转换技术
【发布时间】:2009-07-16 13:30:37
【问题描述】:

我有一个关于技术和实现的问题,而不是要解决的实际问题。最近我创建了一个抽象类,我们称之为A,它定义了它的子类的共同行为。

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

在 Java 中,我使用 instanceof 来检索真实类型,但最终我不得不对真实类型进行大量转换,这看起来很乱。有没有人对如何使代码更清洁有任何建议?

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

感谢任何回答的人,非常感谢!

编辑:我用斜体添加了进一步的说明。谢谢。

【问题讨论】:

  • 嗨,我遇到了同样的问题,而且很难用谷歌搜索(我很幸运找到了它)。很长一段时间后,您的经验是否让您明确回答了这个问题?
  • 尽量重载方法,这样你就永远不需要知道真正的类型。只要每个子类都有一个具有不同实现的通用方法,您就永远不需要知道真正的类型。例如如果我有抽象类 Animal 以及扩展 Animal 的 Dog 和 Cat 类,而不是方法 woof() 和方法 meow() 我将创建一个方法 makeSound() 或 speak() 两者都存在。

标签: java casting subclassing instanceof


【解决方案1】:

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

或者我完全没有抓住重点?今天早上我没有喝咖啡。

【讨论】:

  • 重点是两者只共享某些方法。还有许多其他方法和变量只存在于不共享或以任何方式兼容的子类中。我可以在超类中定义它们,但其他类必须将这些变量保持为空,这似乎很糟糕。
  • 这听起来很糟糕,因为你正在编写一个函数,它说“如果它是 B 类,做/得到这个 B 特定的东西。如果是 C,做/得到这个 C 特定的东西。我会将它们分解为特定于 B/C/D 的不同功能。看起来这是一个整体的东西,可能会被分解成单独的功能。
  • 是的,这绝对是我正在考虑的事情。谢谢。
  • 祝你好运,我感觉你没有得到你正在寻找的答案。 :(
  • 实际上,将您的答案和 Yishai 的(导致通过方法重载创建多个方法)结合起来似乎是最好的。我希望人们会提供其他替代方案或批评我的解决方案,但遗憾的是,您不能总是得到您想要的结果。
【解决方案2】:

泛型是用来处理这个的。

考虑以下示例:

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) {}

但这并没有让你摆脱 if 陷阱。这取决于有多少以及它们的不稳定程度,看看在这里是否值得更重的解决方案。

【讨论】:

  • 所讨论的方法完全属于另一个类。它不是属于超类或其任何子类的方法。
  • 方法重载可能是我需要做的。
【解决方案3】:

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

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) 方法的回调

【讨论】:

    【解决方案4】:

    正如一晒所说,它看起来像一种设计气味。如果你有 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) {
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-03
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2020-04-29
      • 1970-01-01
      相关资源
      最近更新 更多