【问题标题】:Java. Type vs Object of a class爪哇。类的类型与对象
【发布时间】:2016-04-02 03:46:56
【问题描述】:

例如,当我有一个类 Rectangle 和一个类 Square。如果类 Square 扩展了 Rectangle,则类 square 是类 Rectangle 的子类。现在说我有代码。 Rectangle shape = new Square(5,6); 我将创建一个对象,但它是 Rectangle 类型,但是使用 square 的构造函数还是 Square 的对象?我的困惑始于类 Square 具有类 Rectangle 的相同方法,但它将使用类中的方法正方形不是矩形类。那么我是否创建了一个 Square 对象,但类型为 Rectangle?

评论:每个人都在生气,因为知道正方形不会扩展矩形,但这是我的老师的示例,纯粹展示了继承,事实上,最后他展示了如果我们使用这段代码,它会产生错误。

【问题讨论】:

  • 顺便说一句,Square extends Rectangle 可能不是一个好主意。虽然在几何中,正方形确实是矩形,但就 API 而言,它们不是。一个矩形可能有setHeightsetWidth 方法,假设设置一个不会影响另一个。但是像setLength 一样的Square,它会同时影响高度和宽度。即使您让它们共享方法名称,其行为也足够不同,以至于让 Square 扩展 Rectangle 可能并不好。
  • @yshavit:只要长宽相等,原则上正方形和长方形没有什么区别。
  • @Makoto 如果您有一个宽度=5 和高度=5 的Rectangle rect,并且您调用了rect.setHeight(2),您希望rect.getWidth() 是什么?我希望它保持在 5,而不是更改为 2。现在,仔细阅读 JavaDocs 可能会发现“更改宽度可能会也可能不会更改高度”之类的内容,但是 (a) 那是@987654321 @ 和 (b) 这使得你的程序更难推理,因为你必须在脑海中保留更多的“也许”。
  • @yshavit:这就是为什么如果你真的想要一个正方形,你会使用更具体的Square。我要说的是,从几何(和可能的实现)意义上讲,只要矩形的长度和宽度相等,那么它就与正方形没有什么不同。 (我的直接偏好是让形状然后 不可变 这样你就不会得到那些不稳定的行为,但是......)
  • yshavit 关于它不是一个好主意的说法是有道理的如果类是可变的 - 也就是说,如果你的 Rectangle 真的要提供以下能力在运行时更改其大小。但是在很多应用程序中,它是不可变的——你在构建它时设置了高度和宽度,并且不提供以后更改它们的方法。道德:当您考虑类是否应该是不可变的时,您需要考虑是否要扩展这样的类。

标签: java object types subclass hierarchy


【解决方案1】:

这让很多人感到困惑。让我试着分解一下。

当您说new Square 时,对象是使用Square 构造函数创建的。该对象在其存在期间将具有Square 类型。

当您声明类型为 Rectangle 的变量时,即 Rectangle x;Rectangle x = (anything);,您是在告诉编译器 x(当它不为空时)将始终是对 Rectangle 的引用 或其任何子类(包括Square)。当您说Rectangle x = new Square(...) 时,x 将引用Square,即Rectangle但是x 以后可能会被重新分配为其他 Rectangle,而不是 Square

这意味着,当你说x.method(...) 时,编译器只允许你使用Rectangle 中定义的方法,因为编译器只知道xRectangle 或某个子类。如果你在Square 中声明了一个新方法,你不能在上面的调用中使用它。

但是,如果x 仍然是对Square 的引用,那么当您调用Rectangle 中定义的方法时,程序将实际运行您为Square 编写的方法(如果您已覆盖Rectangle 中的那个)。

也许这个例子会有所帮助。假设Rectangle 声明了public 方法aaabbb。在Square中,你写了一个覆盖方法aaa,你不覆盖bbb,你声明了一个新的公共方法ccc

Rectangle x = new Square(10);
Rectangle y = new Rectangle(5,6);

// assume that x and y aren't changed 

x.aaa();   // runs the overriding method aaa in Square
y.aaa();   // runs the method aaa in Rectangle

x.bbb();   // runs the method in Rectangle, since it's not overridden.  But
           // if bbb calls aaa, then it will call the aaa in Square.
y.bbb();   // runs the method in Rectangle

x.ccc();   // illegal.  Even though the object is actually a Square, the
           // compiler isn't allowed to know that.
y.ccc();   // illegal

((Square)x).ccc();  // This is how you can get to the new method that you
           // declared in Square.  Even though the compiler doesn't know 
           // that x is a Square, when you use the cast, you tell the 
           // compiler that it's OK fo treat it as a Square, and to access
           // the method defined only in Square.
((Square)y).ccc();  // Will throw ClassCastException at runtime, because 
           // y isn't a Square.

希望这会有所帮助。

【讨论】:

  • 谢谢,这回答了我所有的问题:D
  • @stackflow420 如果您认为此答案最能解决您的问题,则应将其标记为答案。目前,这个问题的公认答案是 Epsilon_'s,这意味着这是您所说的最有帮助的答案。这也意味着它是此页面上最高的答案,因此对于从搜索引擎中遇到此问题的任何其他人来说都是最可见的。
【解决方案2】:

您创建了一个 Square 类型的对象。

new Foo(...) 的调用将总是创建一个 Foo,没有例外。它总是会调用Foo 的构造函数,同样没有例外。也就是说,如果 Foo 从另一个类扩展,那么 Foo 的构造函数要做的第一件事就是调用超类的构造函数。同样,永远没有例外——尽管您不一定会在代码中看到它,因为如果您没有调用 super(...) 并且超类中存在无参数构造函数,那么编译器会自动为您调用该构造函数。但无论如何,它总会被调用。

由于您已将 Square 设置为矩形,因此该对象也是 Rectangle 的实例。对于您的类,Square 始终是 Rectangle,但并非所有 Rectangle 都是 Squares。

Rectangle shape 位仅表示就编译器 所知,它“至少”是一个矩形。它可能完全是一个 Rectangle,或者它可能是 Rectangle 的一个子类(如 Square)——但它不会是,例如,一个 Number。

当您调用shape.getArea()(例如)时,JVM 将查找shape实际 类型——不仅仅是它的编译时类型,而是它实际创建时的类型当您调用 new 时——并调用该类定义的方法。

【讨论】:

    【解决方案3】:

    继承总是给你的对象一个is-a relationship。因此,凭借Square 扩展Rectangle,可以肯定地说Square is-a Rectangle

    您已经创建了Square 的实例,但您将只能在其上使用其父级Rectangle 提供的方法。

    【讨论】:

    • 所以你是说你不能调用属于 Square 的方法?
    • 如果您将Square 的实例称为Rectangle,那就对了。因为父类不知道子类的方法,所以子类定义的任何东西都不能被父类使用。
    【解决方案4】:

    您正在寻找的是对“Square 真的是矩形吗?”问题的答案。从几何学的角度来看,答案是肯定的,但从软件的角度来看,答案可能并不那么明显。 “Is-a”关系必须遵循Liskov Substitution principle

    所以本质上,如果基类有一些不适用于派生类的方法,那么它就不是“is-a”关系。

    例如

    类矩形{

    /构造函数代码/

    public void changeWidth(){....} public void changeLength(){....}

    }

    changeWidth 和 changeLength 是两个函数,它们对矩形非常有意义,但对 Square 则不然,因为正方形的所有边都相等。虽然你可以破解并在 square 类中给出你自己的两个函数的实现,但从我的角度来看,关系看起来并不自然。

    至于其他答案,我同意他们。

    【讨论】:

      【解决方案5】:

      这叫做多态,做你的功课。 shape 变量只是一个参考,实际对象是 Square 对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-01
        • 1970-01-01
        • 2011-01-07
        • 1970-01-01
        • 2011-09-24
        • 2012-10-07
        • 2020-07-25
        • 1970-01-01
        相关资源
        最近更新 更多