程序清单:
package com.yjk;
public class Parent
{
//定义一个名为i的实例变量
private int i = 1;
public Parent()
{
this.display();
}
public void display()
{
System.out.println(i);
}
}
---------------------------------------------------------------------
public class Son extends Parent
{
//定义一个名为i的实例变量
private int i = 2;
//构造器,将实例变量i初始化为3
public Son()
{
i = 3; //⑵
}
public void display()
{
System.out.println(i);
}
}
---------------------------------------------------------------------
package com.yjk;
public class Test {
public static void main(String[] args)
{
//创建子类实例
new Son(); //⑴
}
}
}
---------------------------------------------------------------------
这行代码会调用子类Son里的构造器,由于子类Son继承了父类Parent,而且子类Son的构造器中,并没有显示的使用Super
调用父类Parent的构造器,因此系统会自动调用Parent类中的无参构造器来执行初始化。
在父类Parent的无参构造器中,只是调用了display方法来向控制台输出变量i的值,但是结果却为0。
OK,那么到此,如果你知道是为什么,就可以略过以下内容,反之,请耐心的滚动你的鼠标:
当程序运行至1处时,系统为Son实例对象分配了两块内存空间,是的,换言之就是说,Son对象拥有2个名为i的实例变量
声明:
永远记住,构造起只负责对 实例对象的变量进行赋值 ,别无它用。构造器不是用来创建对象的,不是,真的不是!
其实在构造器执行之前,系统已经为该对象分派好内存了,此时此刻,内存中的所有变量值都为默认值,比
如:0,false,null.
言归正传,系统为Son对象分配了2块内存,分别用于存放变量i,其中一个属于Parent类定义的i实例变量,另一个属于
Son类定义的i实例变量,此时此刻,二者的值都为0;
接下来,便是先执行父类的构造器对其值进行赋值操作。Parent中定义i的时候便对其进行了初始化操作,且值为1.接着便
执行display()操作,OK,问题来了人,该方法this.diaplay() 中的this 是谁?对,此时还是不够混乱,OK,我们对Parent做
一点小修改:
package com.yjk;
public class Parent
{
//定义一个名为i的实例变量
private int i = 1;
public Parent()
{
System.out.println(this.i);
this.display();
}
public void display()
{
System.out.println(i);
}
}
再次运行,我们可以得到1,0;此刻是不是觉得更加混乱了?
揭秘:
当this在构造器中出现的时候,它所代表的正是当前初始化的实例对象,此时的this位于Son的构造方法中,但是代码们
却出现在父类Parent的构造方法中,那么系统便在Son构造器中,隐式的调用父类Parent构造器中的代码,故,此时的this
是Son对象,既然如此,它输出的却是父类对象的值,这是因为该行代码位于Parent类型中的构造器中,故其编译类型是
Parent,而它实际引用Son了对象.
下面对其进一步进行解释:
package com.yjk;
public class Parent
{
//定义一个名为i的实例变量
private int i = 1;
public Parent()
{
System.out.println(this.i);
this.display();
System.out.println(this.getClass());
}
public void display()
{
System.out.println(i);
}
}
---------------------------------------------------------------------
“
当变量的编译时的类型和运行时的类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该
变量的类型决定。但通过该变量调用它引用的对象的实例方法时,该方法行为将由它实际引用的对象来决定。因此,当
程序访问this.i时,将会访问Parent类中定义的i实例变量,也就是输出1;但执行this.display()方法时,则实际表现出Son对
象的行为,也就是输出Son对象的实例变量,即 0.
”—李刚
看一次可能不能完全接受,多看即便就好了,最后,希望这个帖子能够为你带来一定的收获。
分享到:
相关推荐
java多态性详解——父类引用子类对象
NULL 博文链接:https://2528.iteye.com/blog/1523901
有关子类和父类。A是子类,Teacher是父类。A是Teacher 的一种(子类)会继承父类李非私
父类赋值给子类的一个小方法,仅供学习参考...
java多态性详解——父类引用子类对象.pdf
论JAVA继承机制中父类与子类的关系
如果一个类继承一个父类,那么子类会拥有父类所规定的所以成员 子类还可以拥有父类没有的独有成员 父类可以完成的任务,子类对象也可以完成 子类可以调用父类Person p= new student(); 声明父类变量,实例化子类...
java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...
父类引用子类对象,父类对象和子类对象之间的引用关系和区别
利用C#反射将子类舍弃多余的属性转换为父类,用途比较少。
c#切换执行程序顺序,有些中级开发小伙伴还是搞不太明白在继承父类以及不同场景实例化的情况下,父类和子类的各种方法的执行顺序到底是,多年c#经验总结
java代码-使用java解决父类与子类的声明应用的源代码 ——学习参考资料:仅用于个人学习使用!
java定义父类和子类.doc
java 子类对象赋值给父类对象的使用,包括代码及详解,个人笔记
java反射获取所有属性,获取所有get方法,包括子类父类,以及包括List集合类
java,定义父类和子类.pdf
NULL 博文链接:https://happywaterlife.iteye.com/blog/1567461
【java】父类声明子类实例化.mhtml
如果一个方法在子类的实例中被调用,或者一个属性在子类的实例中被访问,但是该方法或属性在子类中并不存在,那么就会自动的去其父类中进行查找。 继承父类后,就能调用父类方法和访问父类属性,而要完成整个集成...