我有以下示例代码解释样本多态性概念 - 覆盖
class Super
{
public int number = 1;
public char superText='a';
public String getColor()
{
return "red";
}
}
class Sub extends Super
{
public int number = 2;
public char subText='b';
public String getColor()
{
return "blue";
}
}
public class Sample2
{
public static void main(String[] args)
{
Super supersub = new Sub();
System.out.println( supersub.getColor() + supersub.number + supersub.superText );
}
}
输出为blue1 .
Question 1:
重写派生类getColor()中的Method,并显示Super类的Field .
有人可以解释为什么不调用派生类中的数字字段?即输出为蓝色2
Question 2: 关于记忆分配
对于下面的对象实例化,
Sub subobj = new Sub();
字段'number'的内存在堆中分配,Number变量的地址分配给对象引用subobj .
考虑以下情况,
Super supersub = new Sub();
(a) 这里创建变量的内存,派生类'Sub'中的'number and subText',变量的地址放在supersub对象中
当我访问,supersub.subText我得到错误,无法解析subText .
因此,请解释上面描述的 POINT (a) ,即Derive Class变量的Memory Allocation
谢谢,Cyborgz
5 回答
Java中的字段不会被调用,并且永远不会受到动态调度/运行时多态性的影响 . 在您的情况下,实际上有两个单独的字段碰巧具有相同的名称:
Super#number
和Sub#number
.Sub
类继承Super#number
,因此它具有 both ,您访问哪一个取决于您访问它的变量的 static compile-time 类型 . 这就解释了为什么subobj
访问另一个superobj
.那是因为
fields
不是多态的 . 访问特定引用上的字段时,可以访问引用类型中定义的字段,并且决策不基于实际的对象类型 .No ,
number
是基本类型int
,并且未在堆上分配基元 . 它们存储在文字池中 . Primitives和Wrapper类是两个不同的东西 . 如果您使用Integer
而不是int
,那么您将在Heap
上创建对象,如果该值不在范围内,则由Java
文字池缓存 .这可以从你对第一个疑问的解释中得到证实 . 由于字段访问是基于引用类型解析的,而不是基于实际对象类型 . 所以,显然你不能在
Super
引用上访问subText
,因为该字段不是该类的一部分,而是子类的一部分 .简单地说,因为你无法覆盖字段 . 这些方法是唯一可以被覆盖的东西 .
您不会在Java中覆盖类变量:您隐藏它们 . 覆盖是例如方法 .
字段无法覆盖 . 即使两个类共享父子关系,这些字段也属于它们所定义的类,即使它们与继承字段共享名称也是如此 . 换句话说,
Sub
中的number
与Super
中的number
完全不同 .存储在
supersub
中的对象的类型为Sub
,但编译器不知道这一点 .因为Java是一种静态类型语言,所以编译器会使用引用的声明类型(即变量类型),因为在大多数实际情况下,运行时类型(在
new
表达式中显而易见的那种)不是'必须在编译时知道 . 例如,您可能从另一个方法或两个或三个候选方法获得此对象,因此运行时类型是不可预测的 .将引用存储在超类变量中意味着您打算将该对象用作
Super
一段时间 . 然后,编译器会根据您的这种感知意图进行工作 .Super
不保证只有运行时类型为Sub
的实例,因此它无法做出您期望的假设 .话虽如此,将引用存储在一种变量或另一种变量中并不会修改对象 . 如果您要将对象强制转换为实际知道您尝试访问的那些成员的类型的变量(在您的情况下,
Sub
类型),那么您仍然存在(并且它们保留其值) .