黑马程序员技术交流社区
标题: 对象变量的访问,我见鬼了,求牛人解释!!!! [打印本页]
作者: 周毅中 时间: 2012-4-25 09:31
标题: 对象变量的访问,我见鬼了,求牛人解释!!!!
先上代码,大家看看到底i是多少?- public class MyTest {
- public static void main(String[] args) {
- new Dog();
- }
- }
- class Animal {
- private int i = 2;
-
- public Animal() {
- this.display();
- }
-
- public void display() {
- System.out.println(i);
- }
- }
- class Dog extends Animal {
- private int i = 22;
-
- public Dog() {
- i = 222;
- }
-
- public void display() {
- System.out.println(i);
- }
- }
复制代码 求牛人解释。。。怎么也猜不到打印的竟然是0。
作者: 王勃 时间: 2012-4-25 09:39
哥表示,能解答,在调试中。。。。。稍等哈
作者: 刘永菲 时间: 2012-4-25 09:40
调试了一遍,关系明确,看不出什么问题,同惑,共求解。
作者: 王勃 时间: 2012-4-25 09:42
本帖最后由 王明(1988) 于 2012-4-25 09:45 编辑
看来见鬼的不是你啊,是你被鬼玩了。哈哈哈哈{:soso_e144:}{:soso_e144:}
我给程序加了注释,你仔细看下啊,给你上我改过的(加注释了)代码:- package com.heima;
- public class MyTest {
- public static void main(String[] args) {
- new Dog();
- }
- }
- class Animal {
- private int i = 2;
- public Animal() {
- //由于你创建的是Dog对象,要明白this在这里究竟指向谁?我调用getClass()来看看
- System.out.println(this.getClass());
- this.display();
- }
- public void display() {
- System.out.println("Animal的display方法");
- System.out.println(i);
- }
- }
- class Dog extends Animal {
- private int i = 22;
- public Dog() {
- super();//加上super()是为了更直观点
- i = 222;
- }
- public void display() {
- System.out.println("Dog的display方法");
- System.out.println(this.i);
- }
- }
复制代码 现在给你解释。
首先new Dog();这时jvm给你在堆内存中申请空间,此刻i=0,而在调用父类构造方法之前,先去初始化实例变量的值和初始化块(先静态,后非静态),这时在进入构造函数之前i被初始化为2(这个i作为一份拷贝存在Dog当前对象中)。进入父类构造方法后,由于你使用this.display();你用到了this,这很关键,要明白this究竟指向谁呢?很显然this指向的不是Animal而是Dog(虽然这个this你写在Animal中),所以接下来调用的是Dog的display()方法而不是Animal的display()方法,在Dog的display方法中你打印i的值(注意这是的打印的i不是之前的拷贝,是原始的i),由于此i是在Dog类中,并且在Dog中没有进行初始化,所以仍是0,当this.dispaly();完了之后要先初始化Dog的实例变量值,这是i(不是拷贝i,拷贝i为2)为22,执行Dog构造方法中的i=222;后i(不是拷贝i)为222。注意哦亲,你的打印语句是在Dog的display方法里面,i是那时的i非此时的i。
其实你可以给程序加断点,进行调试跟踪,对i的变化那是一目了然。等会给你上图。。。
作者: 王勃 时间: 2012-4-25 09:43
代码忘上了等我修改
作者: 王勃 时间: 2012-4-25 09:51
表示你这个问题,很经典,很能说明对象在创建时,变量时怎么变化的。。。。
现在给你上我调试的图片,有图有真相。。。。。。我在其中加了断点,你注意哦,绿色的断点。
1.
作者: 王勃 时间: 2012-4-25 10:04
2.我step into(F5)进入父类,在调用父类构造方法前,先实例化拷贝i,注意变化哦,
F6后,上图:
作者: 王勃 时间: 2012-4-25 10:25
好,图片能看清楚,我继续。。。。
直接上图了,不文字说明了。
见证奇迹的时刻到了。输入的是0。
下来的i变化,你自己跟踪调试,我就不上图。已经打印你的i了,之后i会变成22,再变成222,此时i非彼时i。
调用毕老师的话,O了。{:soso_e128:}{:soso_e128:}
作者: 周毅中 时间: 2012-4-25 10:38
感谢王同学的解答,对于对象的创建,以及其中变量的变化,我从此不会迷糊,也调用毕老师的一句话:O了。
作者: 沈样 时间: 2012-4-25 10:40
我是这样分析不知道对不对,new Dog();这个会在堆内存中先找到Dog.class并加载进来,但是在加载之前,方法区内的方法就已经加载了,因为public Dog() 的构造方法中在
i = 222;之前是先调用父类的默认构造方法,在父类默认函数调this.display() 时,this是调用他的类,即dog类的display,所以打印的是dog的i,因为方法区内的要先于对象创建,
所以调用时i还没初始化,如果加static关键字加载到方法区内,就能打印出i的值,不过在这里我也不太确定,因为属性初始化要先于构造函数,有知道的兄弟也发个信息给我,
共同学习一下
作者: 李斌 时间: 2012-4-25 10:50
学习了~~
作者: 沈样 时间: 2012-4-25 10:53
在网上找了一下,或许可以解释一下:(1)设置成员的值为默认的初始值(0,false,null)。
(2)调用对象的构造方法(但是还没有执行构造方法体)。
(3)调用父类的构造方法。
(4)使用初始化程序和初始块初始化成员。
(5)执行构造方法体。
这样就可以解释为什么构造方法前为什么没有初始化成员值
作者: 王勃 时间: 2012-4-25 10:59
本帖最后由 王明(1988) 于 2012-4-25 11:00 编辑
额,沈同学,加载顺序你错了,还有方法区的理解也有问题、、、、
在加载main方法后,静态变量不管父类还是子类的都执行了,然后才是父类和子类的的普通变量和构造器。这是因为,当要创建子类这个对象时,
发现这个类需要一个父类,所以把父类的.class加载进来,然后依次初始化其普通变量和初始化代码块,最后才是构造器,然后可以开始子类的工作,
把子类的.class加载进来,在做子类的工作。而方法区的代码是存放代码的地方,虽然jvm在程序执行前将代码放进去,但代码是静态的,还没真正执行,在执行时,初始化Dog中的i为默认的0.这个样子。
给你一个静态变量,静态初始化块,和普通变量,以及构造器的加载顺序:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
*************in main***************
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
*************second subClass***************
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
作者: 王勃 时间: 2012-4-25 11:00
我给你代码,你自己看看吧>>>>>
作者: 王勃 时间: 2012-4-25 11:07
代码:- package com.heima;
- class Parent {
- // 静态变量
- public static String p_StaticField = "父类--静态变量";
- // 变量(其实这用对象更好能体同这一点,如专门写一个类的实例)
- // 如果这个变量放在初始化块的后面,是会报错的,因为你根本没有被初始化
- public String p_Field = "父类--变量";
- // 静态初始化块
- static {
- System.out.println(p_StaticField);
- System.out.println("父类--静态初始化块");
- }
- // 初始化块
- {
- System.out.println(p_Field);
- System.out.println("父类--初始化块");
- }
- // 构造器
- public Parent() {
- System.out.println("父类--构造器");
- }
- }
- public class SubClass extends Parent {
- // 静态变量
- public static String s_StaticField = "子类--静态变量";
- // 变量
- public String s_Field = "子类--变量";
- // 静态初始化块
- static {
- System.out.println(s_StaticField);
- System.out.println("子类--静态初始化块");
- }
- // 初始化块
- {
- System.out.println(s_Field);
- System.out.println("子类--初始化块");
- }
- // 构造器
- public SubClass() {
- // super();
- System.out.println("子类--构造器");
- }
- // 程序入口
- public static void main(String[] args) {
- System.out.println("*************in main***************");
- new SubClass();
- System.out.println("*************second subClass***************");
- new SubClass();
- }
- }
复制代码 输出结果:
作者: 王勃 时间: 2012-4-25 11:12
总之,原理都是文字,那里有实践来的更直接啊,所以i是多少,自己断点调试跟踪,一目了然,这个问题到此,大家都一起O了吧。。。。
{:soso_e128:}
作者: 高彰谦 时间: 2012-4-25 11:14
王明讲的已经非常清楚了,我就不多赘述了,支持王明的讲解,实在是很给力啊!
作者: 王勃 时间: 2012-4-25 11:26
哥表示是1988年的王明,论坛里还有和我重名的,注册王明不成功,郁闷的很那,只能说老爸太崇拜导致长征的左倾罪人啊。
送上一句:保持写下梦想时的状态,不要因为一开始的失败而放弃,80后三十而立,为明天伏笔,今天只有努力。
一起向上吧,少年!
作者: 陈忠 时间: 2012-4-25 11:52
王明(1988) 发表于 2012-4-25 11:07 
代码:输出结果:
理解的那是一个透彻啊 ,佩服!
作者: 罗旭维 时间: 2012-4-25 12:00
我也改了一份代码,这份代码可以找到根本原因:- package test;
- public class MyTest {
- public static void main(String[] args) {
- new Dog();
- }
- }
- class Animal {
- private int i = 2;
-
- public Animal() {
- System.out.println(this.getClass().getName());
- this.display();
- }
-
- private void display() {
- System.out.println("Animal method");
- System.out.println(i);
- }
- }
- class Dog extends Animal {
- private int i = 22;
-
- public Dog() {
- this.i = 222;
- }
-
- private void display() {
- System.out.println("Dog method");
- System.out.println(this.i);
- }
- }
复制代码 修改只是将display声明改为private,结果是Animal构造函数里的this指针的确是子类Dog的,但调用的display方法却是Animal!这似乎乱套了?
关键在于java虚函数的机制,子类重新定义了display方法,用多态的机制解释,当创建的是子类对象那这个display调用的就是子类定义的display。
实际可以理解为子类的方法覆盖(替换)了父类的方法,没有产生新的方法。而声明改成private后,私有成员不能外界(包括子类)访问,所以子类虽然重新定义了display方法,但他没有覆盖(替换)掉原来的display方法,而是产生了一个新的方法。
在java里你声明了一个类一个方法那它的所有代码都固定了,代表java类的那一段字节码是不会变的。
Animal构造函数的代码也是固定的。里面调用的display方法单纯的理解也是一个函数地址(标识、函数名),不管写成this.display()还是就只写成display(),它调用的还是那个函数。在声明为public的情况下display被子类重新定义的方法覆盖(替换)了,所以调用的是子类实现的display。而在声明为private的情况下,编译器是以某种规则产生了新的方法,子类的display有新的函数地址(标识、函数名)。父类Animal的构造函数方法代码又没变化,所以它调用的还是父类那个display。
作者: 王勃 时间: 2012-4-25 12:16
罗旭维 发表于 2012-4-25 12:00 
我也改了一份代码,这份代码可以找到根本原因:修改只是将display声明改为private,结果是Animal构造函数里 ...
修改只是将display声明改为private,结果是Animal构造函数里的this指针的确是子类Dog的,但调用的display方法却是Animal!这似乎乱套了?
这不可能,我测试了你的代码,明明是Dog的display()方法被调用。。。。
看图:- package com.heima;
- public class MyTest2 {
- public static void main(String[] args) {
- new Dog();
- }
- }
- class Animal2 {
- private int i = 2;
-
- public Animal2() {
- System.out.println(this.getClass().getName());
- this.display();
- }
-
- private void display() {
- System.out.println("Animal method");
- System.out.println(i);
- }
- }
- class Dog2 extends Animal2 {
- private int i = 22;
-
- public Dog2() {
- this.i = 222;
- }
-
- private void display() {
- System.out.println("Dog method");
- System.out.println(this.i);
- }
- }
复制代码 我把名字改成都加2,因为我的包里之前有个Animal和Dog,冲突了。
输出结果:
作者: 王勃 时间: 2012-4-25 12:21
关键在于java虚函数的机制,子类重新定义了display方法,用多态的机制解释,当创建的是子类对象那这个display调用的就是子类定义的display。
实际可以理解为子类的方法覆盖(替换)了父类的方法,没有产生新的方法。而声明改成private后,私有成员不能外界(包括子类)访问,所以子类虽然重新定义了display方法,但他没有覆盖(替换)掉原来的display方法,而是产生了一个新的方法。
在这个例子里,只创建了子类,并没有调用什么display方法,拿多态解释是错误的,亲,new Dog()这个对象还没调用任何方法,只是在构造器中调用类中的成员方法,你觉得这事情跟多态有关系吗!!!!!
作者: 王勃 时间: 2012-4-25 12:24
罗旭维 发表于 2012-4-25 12:00 
我也改了一份代码,这份代码可以找到根本原因:修改只是将display声明改为private,结果是Animal构造函数里 ...
你试试吧,虽说子类访问父类的private 方法不行,我在构造对象时就调用,你觉得我就不能调用了吗?
那你说单例模式有该如何解释。。。。
作者: 罗旭维 时间: 2012-4-25 12:36
王明(1988) 发表于 2012-4-25 12:24 
你试试吧,虽说子类访问父类的private 方法不行,我在构造对象时就调用,你觉得我就不能调用了吗?
那你 ...
这位同学,我不觉得我哪里有问题,我这边运行没问题,用的是1.6的jdk。
作者: 王勃 时间: 2012-4-25 12:39
那,我表示我见鬼了。。。。{:soso_e120:}
作者: 罗旭维 时间: 2012-4-25 12:40
王明(1988) 发表于 2012-4-25 12:24 
你试试吧,虽说子类访问父类的private 方法不行,我在构造对象时就调用,你觉得我就不能调用了吗?
那你 ...
这些是基础知识。
作者: 王勃 时间: 2012-4-25 12:41
罗旭维 发表于 2012-4-25 12:36 
这位同学,我不觉得我哪里有问题,我这边运行没问题,用的是1.6的jdk。
我copy你的代码,只改了个2,就这样,你仔细看看。。。
不是你见鬼了,就是我见鬼了。。。
作者: 王勃 时间: 2012-4-25 12:42
罗旭维 发表于 2012-4-25 12:36 
这位同学,我不觉得我哪里有问题,我这边运行没问题,用的是1.6的jdk。
我的意思主要是,你用多态来解释是错误的,这里还未曾体现出多态。。。
仔细想想哦。。。
作者: 罗旭维 时间: 2012-4-25 12:44
王明(1988) 发表于 2012-4-25 12:42 
我的意思主要是,你用多态来解释是错误的,这里还未曾体现出多态。。。
仔细想想哦。。。 ...
受够了,好吧,我无语。
作者: 王勃 时间: 2012-4-25 12:49
本帖最后由 王明(1988) 于 2012-4-25 14:30 编辑
罗旭维 发表于 2012-4-25 12:44 
受够了,好吧,我无语。
额,我运行n遍,还是上面的结果。。。
作者: 罗旭维 时间: 2012-4-25 13:04
王明(1988) 发表于 2012-4-25 12:24 
你试试吧,虽说子类访问父类的private 方法不行,我在构造对象时就调用,你觉得我就不能调用了吗?
那你 ...
我还是提醒下你吧,如果你运行的是你贴出来的代码,那请注意你的代码,你测试新建了Dog2类但在main函数里你new 的是Dog类!
作者: 王勃 时间: 2012-4-25 13:10
罗旭维 发表于 2012-4-25 13:04 
我还是提醒下你吧,如果你运行的是你贴出来的代码,那请注意你的代码,你测试新建了Dog2类但在main函数里 ...
额,我错了,多谢提醒。刚才因为Dog2只改了类,没改new Dog2();又调到我包里面的那个Dog类中去了。
嗯,不过我认为这个例子没涉及到多态,因为我没用new Dog2()去调用方法。你认为呢,,,
作者: 王勃 时间: 2012-4-25 13:11
罗旭维 发表于 2012-4-25 13:04 
我还是提醒下你吧,如果你运行的是你贴出来的代码,那请注意你的代码,你测试新建了Dog2类但在main函数里 ...
再次表示,罗同学很细心啊,谢谢:'(
作者: 真真姐 时间: 2012-4-25 15:26
本帖最后由 杨国祯 于 2012-4-25 17:35 编辑
这个问题看到,兄弟们很纠结啊!!
不同的看法实际上很正常,真理就是一个讨论的过程才出来的,说实话大家的解释我没怎么看,因为思路不一样!
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这几天实际上大家搜搜这一类的我有几个回答,加起来会综合的理解,今天的这个不仅仅是执行顺序的问题,还有子类父类的问题,可能部分比较复杂!这里简单的简述下:- 这里简单谈谈我的看法!我们要理解程序中代码的加载顺序 :静态块——>静态变量——>成员变量——>构造方法——>静态方法(执行到才加载)
- 一个完整执行过程都是这样的,本例中没有任何的静态变量,静态方法;当前过程中的变量,比如i只有执行到了才会加载,所以就是一个正常的执行过程
复制代码 所以执行顺序是:- A、执行new Dog();
- B、执行Dog()无参构造方法,执行里面默认的super(),为什么会这样说,看我的其他回复,解释的很详细!
- C、到super()这了,当然要去看看父类有什么指示,跳转至Animal()无参构造函数,由于父类重写了系统默认提供的无参的构造函数,所以要先执行父类构造函数里面的语句!
- D、继续执行,这里的this注意是指代的谁,记得这句话谁调用就指代谁,这里可以用 this.getlass()检测 , 看结果,这里肯定是Dog,所以this指代Dog
- E、这是一个容易搞糊涂的地方,注意了 this既然是Dog类,这里注意子类的方法是不是跟父类的方法同名,这是什么呢,是不是重写啊, 子类的方法对于父类的方法重写了,你说执行谁的方法!
- F、最后执行子类重写的方法,子类的变量加载了没,还没有,但是系统会给赋初值,i是多少当然是0,所以结果就出来了
复制代码- 王明(1988)童鞋,debug模式写的很好,我不知道他的是不是跟我的一样,但是他用的方法很好值得推广
复制代码 扩展:- 这里如果把,两个变量都变成static的猜猜结果会怎么样
- private static int a = 2
- private static int a = 22
- 注意:你会发现结果不是0了, 是22了,为什么现在知道了吧,因为执行顺序,静态变量先加载了,才执行的new Dog()!!
复制代码 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里是综合的知识点,对于基本的东西一定深挖,这样才能理解透彻!!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
最后用代码给你们标注请代码执行过程:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public classMyTest
{
public static void main(String[] args)
{
new Dog(); //第一步
}
}
class Animal
{
private int i = 2;
public Animal() //第四步,跳过来发现父类重写了系统默认的无参构造方法,于是执行里面语句
{
this.display(); // 第五步,发现this是代表Dog,知道为什么吗! 因为谁调用就代表谁,这个忘了没,上面刚提到了!不信?自己getClass。
}
public void display()
{
System.out.println(i);
}
}
class Dog extends Animal
{
private int i = 22;
public Dog() // 第二步
{ //super // 第三步,这里系统默认提供了一个super(),为什么,记住一句话,子类要去请示父类,是系统默认的
i = 222;
}
public void display() // 第六步 为什么是这,毕老师要敲你了啊,方法名一样,参数一样是什么,是不是重写,重写怎么执行!
{
System.out.println(i); // 第七步,给 i 赋值的代码块执行到了没,没有吧,i的值是多少,是不是系统默认提供的!
}
}
这样的话是不是清晰了呢,执行过程有时候就是比较复杂,但是我们知道了之后发现过程应该按照语法来,是不是!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
还有两种增补情况,帖子太长,不让发,只好另外书写,请看下一贴!!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
作者: 王勃 时间: 2012-4-25 15:51
本帖最后由 王明(1988) 于 2012-4-25 15:52 编辑
杨国祯 发表于 2012-4-25 15:26 
这个问题看到,兄弟们很纠结啊!!
不同的看法实际上很正常,真理就是一个讨论的过程才出来的,说实话大家 ...
我们先简单的程序中代码的加载顺序 :静态块——>静态变量——>成员变量——>构造方法——>静态方法(执行到才加载)
额,后面的对前面的就错了,静态块,静态变量这个顺序是和你在类中写的顺序相关的!不是绝对的静态块在前,静态变量在后,你可以试一下,静态变量写在静态初始化块前面,顺序就反过来了。
嗯,你总结的A,B,C,D,E,F很简洁,但你调试会发现,里面this下面有两个 i ,我的理解是,下面的是拷贝,
上面的是原始 i 。因为new的是Dog类,应该只有一个实例变量,那么多的一个,我的理解是拷贝,因为父类并没有实例化啊,你认为呢?
还有这里如果吧 两个变量都变成static的猜猜结果会怎么样
既然new了对象,咱们去搞静态的类变量,好像没人这么干吧,不过你说的是对的。实际开发没人这么干滴。。。
作者: 真真姐 时间: 2012-4-25 16:20
本帖最后由 杨国祯 于 2012-4-27 10:43 编辑
一定要深入理解相关知识,知道你混淆概念了,应该很多人有这个疑问,- 比如说静态块,什么是静态块,是静态函数吗!其实不是的
- static {
- }
- 就是一个静态块,里面有相应的语句,他绝对是第一位加载的,不论你放到哪里这个一定要注意!!
复制代码 我有另一个回复,专门介绍执行顺序,有心的童鞋可以去看看,里面总结的很详细!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
接上一贴:增补两种情况,童鞋们看了会有益处的!!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第一种 在问题的例子里面 既然 Dog的 i 变量是0,那么Animal中的变量 i 是多少呢!,这个问题有没有想过
有个童鞋可能会说,Animal中的变量也不是静态的不会提前加载,当然也是o了,这样想的话就出错了,其实Anmal中的i的值是2,
不好理解吧! 接着看,
先抛开继承不说,我们就只有一个方法,我们在自己的方法里面实例化一个对象,执行的时候是怎么执行的清楚吗?
实际上执行的时候,每new一个当前类对象 如 Animal ani = new Animal的时候,都需要吧Animal这个类里面的所有属性执行一遍,然后在执行构造方法,
你又问为什么呢?不这样的话你说Animal类的对象的属性从何而来,不都是系统的默认值了吗
class Animal
{
private int i = 2; // new Animal()的时候我们会发现这个第一个执行,为的就是给Animal加载属性值
public Animal() //然后这个是第二步
{
this.display(); // 这个是第三步,这里的 this是谁,很简单的,谁调用就是谁
}
public void display()
{
System.out.println(i); //打印出来的i是多少呢? 当然是2了,不然你new出来的对象都没有属性,还如何操作!
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二种
大家注意看这里的代码都是 private的,有的同学会想了,我要是吧private改成public会怎么样,是不是跟private一样啊 ,因为你打印的是Dog,这里面的变量根本还没有初始化
那你又说了; 我给他们加上static,也就是我补充的,会怎么样呢,答案就是 ,Dog中的i变化了,就是22了
你又有疑问了:你不是说还没执行到 private static int i = 22; 这一句吗,这就是静态变量会提前加载的缘故了,
但是一定注意,提前加载是不是说这句代码不会再执行了吗?不管你怎么理解你记住这句代码 private static int i = 22; 在new Dog()中还没运行,
在执行完Animal中的相应的方法后,Dog中会第一个执行这行代码
class Dog extends Animal
{
private static int i = 22; // 第一步
public Dog() // 第二步
{
i = 222; // 第三步
}
public void display()
{
System.out.println(i);
}
正所谓加载不代表不会运行了,每次实例化的时候仍然会这样的执行一遍,这样的话整个过程是不是更清楚了!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
基本上各种情况也是涵盖了啊,里面内容不少,值得揣摩,这也是个大知识点!
作者: 王勃 时间: 2012-4-25 17:03
杨国祯 发表于 2012-4-25 16:20 
一定要深入理解相关知识,知道你混淆概念了,应该很多人有这个疑问,我有另一个回复,专门介绍执行顺序,有 ...
就是一个静态块,里面有相应的语句,他绝对是第一位加载的,不论你放到哪里这个一定要注意!!
觉得你说的,你说的静态块绝对是第一个加载的,我做了例子,等会我发帖子。你来看。。。这都到第2页,网速不是很快
作者: 黄或俊 时间: 2012-4-25 18:24
王明(1988) 发表于 2012-4-25 09:42 
看来见鬼的不是你啊,是你被鬼玩了。哈哈哈哈
我给程序加了注释,你仔细看下啊 ...
还是有点蒙,this这个我自己理解为是:display()被子类覆盖掉了,可以这样理解吗?
但是就是关于i的初始化,感觉结果是零的话又跟毕老师的初始化顺序有冲突
以下个人理解:
new Dog();
1、加载内存,执行代码块就不说了直到开辟空间分配地址
2、在堆中建立Dog的特有属性,进行默认初始化
3、显示初始化
4、执行构造方法
5、Dog中的第一行有super,所以先执行Animal()
6、Animal()中又用到了子类的display()方法,所以就直接输出子类display()中的语句
【但是这个时候 i 已经显示初始化过了呀!!!】
还没有学过断点调试,所以对于结果纳闷
作者: 王勃 时间: 2012-4-25 18:47
黄或俊 发表于 2012-4-25 18:24 
还是有点蒙,this这个我自己理解为是:display()被子类覆盖掉了,可以这样理解吗?
但是就是关于i的初始 ...
你看我的调试图片。。。。就明白了
| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |