【问题标题】:Java Inheritance IssuesJava 继承问题
【发布时间】:2014-04-28 13:35:41
【问题描述】:

我有一个名为“Shape”的父类,它有一个子类“Circle”。 Circle 类继承了 Shape 的属性,并具有一个附加参数“radius”,以及一个名为 getRadius() 的方法。

最后我有一个“ShapeList”类,它包含一个不同形状的 ArrayList,以及各种添加/删除函数。

我正在尝试打印圆的半径:

System.out.println(shapeArray.getShape(1).getRadius());

shapeArray 是形状列表,getShape 返回一个特定的形状对象。但是,当我尝试使用 getRadius 时,它查看的是 Shape 类而不是特定的 Circle 子类,因此无法识别该方法,我该如何访问半径?

【问题讨论】:

  • 你应该castShape。有关详细信息,请参阅"Inheritance (The Java Tutorials)"
  • 因为它只知道Shape,不知道Circle。
  • 每个人都说你应该投。虽然在技术上是正确的,但我会退后一步,问为什么通用形状列表应该特别注意半径
  • Brian 有一个很好的观点...这就是我在下面提到的最重要的方法...
  • 这是一个通过编译时正确的解决方案解决的问题。基于铸造和反射的解决方案是荒谬的。重写一个方法是愚蠢的——它污染了Shape 的签名并最终创建了一个接口,上面有很多奇怪的疣,以至于没有任何意义。这是访问者模式的确切情况。

标签: java inheritance


【解决方案1】:

你需要把你的形状投射成一个圆圈:

Circle circle = (Circle) shapeArray.getShape(1);
System.out.println(circle.getRadius());

当然,这种做法使拥有父类的全部意义无效。

【讨论】:

  • 另外添加一个 instanceof 检查,因为其他形状也可能存在
  • 原始样本上没有,所以我认为它是在“其他地方”完成的。无论如何,你当然是对的。
【解决方案2】:
System.out.println(((Circle)shapeArray.getShape(1)).getRadius());

【讨论】:

    【解决方案3】:

    您应该将Shape 对象转换Circle

    请注意,当您显式强制转换一个对象时,您是在告诉编译器相信您知道自己在做什么,并且您确定 Shape Circle。如果不是这种情况,您可能会遇到运行时异常。为了避免这种情况,请使用instanceof 运算符。

    我强烈推荐你阅读"Inheritance (The Java Tutorials)"

    【讨论】:

      【解决方案4】:

      您应该在打印前转换为 Circle。您必须注意,这可能会导致 java.lang.ClassCastException!

      简单示例:

      class Shape {
         private String property;
      }
      class Circle extends Shape {
          private int radius;
          public Circle(int radius) {
              this.radius = radius;
          }        
      
          public void setRadius(int radius) {
              this.radius = radius;
          }
          public int getRadius() {
              return this.radius;
          }
      }
      
      
      class ShapeArray {
          public ArrayList<Shape> shapeArray = new ArrayList<Shape>();
      
          public void addShapeToArray(Shape shape){
              shapeArray.add(shape);
          }
          public Shape getShape(int index) {
              return (Shape) this.shapeArray.get(index);
          }
      }
      

      用法:

      import java.util.ArrayList;
      public class Main {
      
          public static void main(String[] args) {
              ShapeArray shapeArray = new ShapeArray();
              shapeArray.addShapeToArray(new Shape());
              shapeArray.addShapeToArray(new Circle(2));
              System.out.println(shapeArray.getShape(0).getRadius());
          }
      }
      

      这段代码不会编译,行

       System.out.println(shapeArray.getShape(0).getRadius());
      

      是问题所在。 您首先需要投射到 Circle,如下所示:

       System.out.println(((Circle) shapeArray.getShape(0)).getRadius());
      

      但是,正如我在开头所写的那样 - 这可能会产生 ClassCastException。所以你需要以某种方式确保你得到的对象实际上是一个 Circle,这样当你投射它时 - 代码不会爆炸。

      【讨论】:

        【解决方案5】:

        打印半径意味着您知道您的特定ShapeCircle

        如果您希望您的程序也知道这一点,您可以通过演员表告诉它:

        Circle circle = (Circle) shapeArray.getShape(1);
        

        现在程序知道circle确实是Circle,你可以使用getRadius()

        【讨论】:

          【解决方案6】:

          你需要投射到一个圆圈。

          Google for Java + Casting...

          虽然您正在做的事情似乎有点困惑 - 我很想为每种类型的形状保留单独的数组,这意味着您可以为圆运行一些代码(比如 getRadius),以及用于多边形的其他特定代码(比如说打印出顶点...)

          您还可以覆盖形状类上的“GetDetails”方法,允许您维护当前拥有的单个数组,但让其上的每个对象返回与其形状类型相关的信息...

          【讨论】:

            【解决方案7】:

            到目前为止,所有答案都违背了在 Java 中使用类型系统的目的。

            了解并使用visitor pattern

            想想你创造了什么:

            • Circle,即“是”Shape
            • 一个容器,可以容纳任何“是”Shape

            这并不意味着容器中的所有内容都是Circle

            当有人在您的容器中放置不是Circle 的东西时,您希望您的程序如何运行?

            强制转换和使用 instanceof 是暗示程序/系统设计不佳的黑客行为。

            【讨论】:

              猜你喜欢
              • 2014-04-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-04
              • 1970-01-01
              • 2011-08-04
              • 2010-09-15
              • 1970-01-01
              相关资源
              最近更新 更多