起因:
在QQ群有人发了这么一段代码,不由地激起了我研究的兴趣。To be frank说实话,我就喜欢这种喜欢写稀奇古怪的代码来实现特定功能的萌新(虽然我自己也是),研究他们的问题总能让我意识到自己基础知识中的不足与疏漏。
分析:
乍一看,这个问题涉及到了类继承与多态。何谓多态?多态的意思 就是 可以将一个子类的引用赋给超累变量,即 一个超类变量可以引用任何一个子类变量。但是此时超量变量无法调用子类中新增的方法(public)。
回到这个萌新的问题来(一下简称这个萌新为他),他的意图就是想验证 多套的特性是否会影响继承的私有域的值。显然,他代码中有基本的语法错误,例如obj.now。。这里不讨论这个,只需加一个get方法就行。
他在超类father中定义了私有域now为“father",在子类test中又定义了同名私有域now为"test"。这是个不好的用法,尽管编译不会报错,但是没有必要重复定义一次。
众所周知,每个子类对象都有名为now的私有域,但是子类无法直接访问超累的私有域。想要访问必须借助公有的接口。因此可以代码改成这样。
class Father
{
private String now="Father";
public void setNow(String a){now=a;}
public String getNow(){return now;}
}
class Test extends Father
{
Test(){setNow("test");}
public static void main(String[] args)
{
Father obj=new Test();
System.out.println(obj.getNow());
}
}
此时输出Test。尽管利将obj声明为Father,但是输出依然是子类特征Test。这就是所谓的“方法具有多态性。
如果我头铁, 按照他的写法,在子类中再一次重复定义同名私有域,并注释掉子类构造器。
class Father
{
private String now="Father";
public void setNow(String a){now=a;}
public String getNow(){return now;}
}
class Test extends Father
{
private String now="Test";
//Test(){setNow("test");}
public static void main(String[] args)
{
Father obj=new Test();
System.out.println(obj.getNow());
}
}
此时输出Father。虽然调用的是子类的构造器,但是似乎子类中的private String now="Test"被屏蔽了,输出的特征与声明对象的特征相一致。为什么会这样呢?这就是所谓的“属性没有多态性”。
书上是这样描述的:下面是调用构造器的具体步骤:
1. 所有数据别初始化为默认值。
2. 按照初始化语句和初始化块对数据初始化。
3. 如果在第一行调用了第二个构造器,则执行第二个构造器的主体。
4. 执行这个构造器的主体
在调用Test()构造器时,私有域是这样被初始化的:Test(super()?
1.now被域初始化语句初始化为"Test"。
2.默认调用超类构造器
3.now私有域又被初始化为"Father"
这应该就是属性没有多态性的根本原因。
在默认调用超类构造器后,执行的并不只有超类构造器的主体,还有超类中的初始化语句。 这与书中的描述有略微不符,或许书中的描述并未考虑到子类构造器的情况吧。
总结:
属性没有多态性,方法有多态性(按照运行子类的方法调用)
千言万语一句话 SGNBBBBBB!!!
对此问题说得更好的是以下博客
Java中类的属性不体现多态性