这是一个关于Java中基本继承的问题,有两个类。
我们有两个类,第一个是Rectangle
:
private double length;
private double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
}
接下来我们有一个名为Square
的扩展类,它扩展了Rectangle
,所以通过super()
我们知道它使用了Rectangle
类的构造函数。
private double side;
public Square(double side)
{
super(side, side);
this.side = side;
}
public void print()
{
System.out.println("I am a square of side " + side);
}
这是我们的主要内容:
Square b = new Square(6.0);
Rectangle c = (Rectangle) b;
c.print();
我们创建了Square
类型的对象,其中包含两个side
double
6.0
个变量
接下来,我们将b
投射到Rectangle
c
,这就是我的问题所在。
为什么c.print()
会打印I am a square of side 6.0
?
答案 0 :(得分:3)
这假定Rectangle
声明了print()
方法。
此操作
Rectangle c = (Rectangle) b;
对b
引用的实例不执行任何操作。它仅将引用变量b
扩展为其超类型Rectangle
。
调用print()
将具有多态行为,并且在运行时,将使用Square
的实现,因为c
引用了Square
对象,该对象已设置为{{ 1}}到size
。
6
请注意,这是自all methods are virtual by default以来Java中的预期行为。在其他语言(如C ++和C#)中,由于Square b = new Square(6.0);
...
private double side;
public Square(double side) {
super(side, side);
this.side = side;
}
中的print
方法未被声明为Rectangle
,因此您的演员阵容会有效。
更多信息:
答案 1 :(得分:1)
这是多态行为。类的实际类型决定了被调用的方法。 Square
的{{1}}版本将被调用,因为对象的实际类型为print
。
答案 2 :(得分:1)
在( Java )继承中,这是预期的行为 - 多态 - 它是您(开发人员)围绕概念(矩形)设计应用程序并允许其他方式的一种方式在使用原始概念(矩形)但具有自己的(方形)行为的地方使用的相关概念(正方形)。
想象一下,您有一个列表或矩形数组,并且您可以使用从您自己的包外部返回的函数来填充它。然后,您将遍历列表并要求每个对象执行操作 - 希望这些对象的行为与实际情况相符是正常的,而不是他们正在填写的内容。
如果你问矩形它的面积是多少,它将乘以长度和宽度并返回结果。如果你不在方形类中覆盖它,它将做同样的事情,但你可以覆盖它,它可以计算它的区域为Math.pow(this.side, 2)
。
这个继承链怎么样:
Shape > Polygon > Quadrilateral > Parallelogram > Rectangle > Square
你肯定需要实现不同的区域计算方法 - 你不希望每个对象的行为都像它自己的底层结构所告诉的那样(而不是表现得像它被投射到的类型) ?
答案 3 :(得分:0)
请记住,c
只是对内存中对象的引用。被引用的对象是动态类型Square,尽管引用c
是 static 类型的Rectangle。静态和动态类型之间的区别对于此示例至关重要。
与对象引用相关联的静态类型是编译器用于确保我们的代码从类型角度理解的含义。但是,当调用对象上的方法时,调用哪个方法取决于对象的动态类型,即在运行时实际引用的对象的类型。这称为动态绑定。
还提到Rectangle-Square示例是规范的。它通常用于说明如何将类型和超类型视为类别和概括可能会产生误导。遵循Liskov替换原则需要使用Rectangle extends Square
以另一种方式编写类。这是面向对象编程的另一个重要思想。
答案 4 :(得分:0)
由于继承,每个Square
也是Rectangle
。当您将其转换为在Square
变量中推送Rectangle
时,它会保留其Square
。在此示例中,Square
或Rectangle
可以放在c
中。多态性意味着将使用真正的任何类的方法。
答案 5 :(得分:0)
我认为这是您需要的修改:
public static class Rectangle
{
protected double length;
protected double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
}
public Rectangle(Rectangle r)
{
this.length = r.length;
this.width = r.width;
}
public void print()
{
System.out.println("I am a rectangle of length " + length + " and width " + width);
}
}
public static class Square extends Rectangle
{
public Square(double side)
{
super(side, side);
}
public void print()
{
System.out.println("I am a square of side " + length);
}
}
public static void main(String[] args)
{
Square b = new Square(6.0);
Rectangle c = new Rectangle(b);
c.print();
}
您的Square
课程与Rectangle
课程无关。它有不同的属性。如果你使用的是继承,那么基类应该继承一些东西。
此外,print()
中没有Rectangle
方法。
一个简单的复制构造函数,使您的基类成员protected
和删除不必要的派生类成员应该有效。