【问题标题】:Basic polymorphism in Java/casting a superclass as a subclassJava中的基本多态/将超类转换为子类
【发布时间】:2014-02-25 18:02:48
【问题描述】:

我正在完成一个 Java 多态性练习,并努力理解类型转换以及如何调用特定于子类的方法。我有一个班狗:

public class Dog
{
    private final String breed;

    public Dog(String b)
    {
        breed = b;
    }

    //More Dog methods (bark, eat, etc.)
}

还有一个可以拉雪橇的子类 SledDog:

public class SledDog extends Dog
{
    public SledDog(String b)
    {
        super(b);
    }

    public void pullSled()
    {
        System.out.println("pulling the sled");
    }
}

在我的申请中,我申报了 3 只狗 - 两只普通狗和一只雪橇犬。我将它们传递给 Dogs 数组,然后循环遍历该数组。如果狗是雪橇犬,我希望他 pullSled() - 但我不知道如何调用该方法,因为它属于子类。我的说明告诉我将数组项转换为 SledDog 对象,但我不知道如何或为什么必须这样做。我认为既然传递给数组的对象已经是一个 SledDog,它应该可以访问 pullSled()。这是我的尝试。

public class DogApp
{
    public static void main(String[] args)
    {
        Dog firstDog = new Dog("Greyhound");
        Dog secondDog = new Dog("Terrier");
        SledDog sledDog = new SledDog("Husky");

        Dog[] dogArray = new Dog[]{firstDog, secondDog, sledDog};

        for(Dog d : dogArray)
        {
            //Makes sense, only want to pullSled() if d is a SledDog
            if(d instanceof SledDog)
            {               
                // This is the part I'm confused about
                d = (SledDog) d;
                d.pullSled();
            }
        }
    }
}

【问题讨论】:

    标签: java inheritance polymorphism subclass


    【解决方案1】:

    你已经很接近了,只需转换它并调用方法:

    ((SledDog)d).pullSled();
    

    if (d instance of SledDog) 条件内。

    另外,我看不到dogArray 的声明。确保您已正确声明和初始化它。

    【讨论】:

    • 所以虽然这个工作 ...这是一个糟糕的设计。将Dog 定义为具有抽象pullSled() 的抽象类,然后在具体子类中覆盖pullSled() 通常是首选方法。至少在Dog 中定义一个pullSlead(),然后在子类中覆盖它。
    • 这成功了!关于 dogArray - 声明似乎没有出现在我上面的示例中,我已经对其进行了编辑以包含它。
    【解决方案2】:

    对象和对对象的引用是有区别的。

    所有 SledDogs 都是 Dogs,但所有 Dogs 都不是 SledDogs。所以按照这个逻辑(就编译器的理解而言),下面的代码就可以了。

    Dog myDog = new SledDog(); // This compiles
    

    同时

    SledDog myDog = new Dog(); // Error
    

    不起作用。


    所以在第一行中,棘手的部分是您有一个 SledDog 类的对象,但您通过 Dog 类的引用来引用它。 (因为所有的 SledDogs 都是狗,这完全没问题)

    但是在这样做的时候,你忽略了它是SledDogness。您将能够访问从Dog 继承的 SledDog 的功能,但 SledDog 的特定功能将不可用。请记住,该对象仍然是 SledDog,但您承认它只是 Dog

    因此,为了访问它们,您必须使用 SledDog 类的引用来引用它。 ---> 因此需要类型转换

    SledDog typeCastedMyDog = (SledDog) myDog;
    

    现在您可以访问 pullSled() 方法了。


    同样的逻辑适用于将它们全部放入 Dogs 数组中。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      在谈论 OOP 时,试图辨别具体的子类实际上是什么通常意味着您做错了什么。

      您可以通过在 Dog 类中定义默认的 pullSled() 然后覆盖它来解决此问题:

      public class Dog
      {
          private final String breed;
      
          public Dog(String b)
          {
              breed = b;
          }
      
          public boolean pullSled()
          {
              System.out.println("Dude, I'm a " + breed + ", not a Siberian Husky!");
              return false;
          }
      
          //More Dog methods (bark, eat, etc.)
      }
      
      public class SledDog extends Dog
      {
          public SledDog(String b)
          {
              super(b);
          }
      
          @Override
          public boolean pullSled()
          {
              System.out.println("pulling the sled");
              return true;
          }
      }
      

      这个简单示例的另一个选项,您还可以定义一个字段和boolean canPullSled()

      public class Dog
      {
          private final String breed;
          protected boolean canPullSled; 
      
          public Dog(String b)
          {
              breed = b;
          }
      
          public boolean canPullSled()
          {
              return canPullSled;
          }
      
          public boolean pullSled()
          {
             if (canPullSled)
             {
                 System.out.println("pulling the sled");
                 return true;
             }
             else
             {
                 System.out.println("Dude, I'm a " + breed + ", not a Siberian Husky!");
                 return false;
             }
          }
      
          // other stuff
      }
      
      public class SledDog extends Dog
      {
          public SledDog(String b)
          {
              super(b);
              this.canPullSled = true;
          }
      }
      

      或者使用 Builder ... 或者 fluent interface ... 或者 ...

      最后,instanceof 真的是万不得已,只有在没有其他办法时才使用。

      【讨论】:

        【解决方案4】:

        如果你需要一个真正的多态案例,你可以使用

        superclassName referenceName=subclassObject
        

        通过这种方式,您可以通过使用超类引用来访问子类的所有方法。

        只是一个提示,让您开始,尝试更进一步 祝你好运!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-05-08
          • 2013-06-30
          • 1970-01-01
          • 2013-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多