[英]Java. Type vs Object of a class
例如,当我有一个Rectangle类和一个Square类时。 如果Square类扩展Rectangle,则Square类是Rectangle类的子类。 现在说我有代码。 Rectangle shape = new Square(5,6);
我将创建一个对象,但是它将是Rectangle类型,但是使用square的构造函数还是Square的对象?,我的困惑始于类Square,它具有与Rectangle类相同的方法,但是它将使用类中的方法方形不类矩形。 那么我是否创建了Square对象,但是具有Rectangle类型?
评论:每个人都知道正方形不会扩展矩形,这让每个人都感到愤怒,但这是我的老师的例子,纯粹显示了继承性,实际上他在演示如何使用此代码如何创建错误。
这使很多人感到困惑。 让我尝试将其分解。
当您说new Square
,将使用Square
构造函数创建对象。 该对象在其整个存在期间将具有Square
类型。
当声明类型为Rectangle
的变量时,即Rectangle x;
或Rectangle x = (anything);
您告诉编译器x
(当它不为null时)将始终是对Rectangle
或其任何子类 (包括Square
)的引用。 当您说Rectangle x = new Square(...)
, x
将是对Square
的引用,即Rectangle
。 但是 ,以后可以将x
重新分配为其他不是Square
Rectangle
。
这意味着,当您说x.method(...)
,编译器仅允许您使用Rectangle
中定义的方法,因为编译器仅知道x
是Rectangle
或某些子类。 如果在Square
声明一个新方法,则不能在上面的调用中使用它。
但是,如果x
仍然是对Square
的引用,那么当您调用Rectangle
定义的方法时,该程序实际上将运行您为Square
编写的方法(如果已覆盖Rectangle
)。
也许这个例子会有所帮助。 假设Rectangle
声明了public
方法aaa
和bbb
。 在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.
希望这可以帮助。
您创建了一个Square类型的对象。
对new Foo(...)
调用将始终创建Foo,没有例外。 而且它将始终再次调用Foo
的构造函数,而不会出现异常。 也就是说,如果Foo从另一个类扩展,那么Foo的构造函数要做的第一件事就是调用超类的构造函数。 再说一次,这也没有例外-尽管您不一定会在代码中看到它,因为如果您没有对super(...)
的调用,并且在super中存在无参数的构造函数类,则编译器将自动为您调用该构造函数。 但是,无论哪种方式,它总是会被调用。
由于已将Square设置为一个矩形,因此该对象也是Rectangle的实例。 在您的课程中,正方形始终是矩形,但并非所有矩形都是正方形。
Rectangle shape
仅表示,据编译器所知,它“至少”是Rectangle。 它可能完全是一个Rectangle,也可能是Rectangle的子类(例如Square),但不会是Number。
例如,当您调用shape.getArea()
,JVM将查找shape
的实际类型(不仅是其编译时类型,而且还包括您在调用new
时实际创建的类型),并调用该方法。该类定义。
继承总是给您的对象一个is-a关系 。 因此,凭借Square
扩展的Rectangle
,可以肯定地说Square
是 Rectangle
。
您已经创建了Square
的实例,但是您将只能在其实例上使用其父Rectangle
提供的方法。
您在寻找的答案是“ Square真的是矩形吗?”。 从宝石学的角度来看,答案是肯定的,但从软件的角度来看,答案可能并不那么明显。 “是”关系必须遵循Liskov替代原则 。
因此,基本上,如果基类具有某些不适用于派生类的方法,则它不是“ is-a”关系。
例如
矩形类{
/ 构造函数代码 /
public void changeWidth(){....} public void changeLength(){....}
}
changeWidth和changeLength是两个函数,它们对于矩形(而不是正方形)非常有意义,因为所有边都相等。 尽管从我的角度来看,尽管您可以在平方类中破解并给出自己的两个函数的实现,但是关系看起来并不自然。
至于其他答案,我也同意。
那就是所谓的多态性,做功课。 shape变量仅是参考,而实际对象是Square对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.