一个让98%java程序员犯难的问题的思考
2010-01-16 15:47
435 查看
源代码:
public class Parent
{
protected void test() {}
public Parent()
{
this.test();
}
public static void main(String[] args)
{
new Child();
}
}
class Child extends Parent
{
private int instanceValue = 1;
public void test()
{
System.out.println("instance value is: " + instanceValue);
}
}
--------------------------------------------
此程序的输出结果为instance value is:0,可能很多人(包括很多老程序员)都会想当然得以为输出结果为1,或者不会有输出,或者认为这个程序本身就是错的(我的老师就是这么认为的,呵呵~)
看了很多有关这个问题的讨论,现在提出一点我的见解:
分析:这个问题首先涉及的知识是类加载分为三个过程:装载、链接、初始化,有关这个知识我在之前的帖子“类加载分为三个过程:装载、链接、初始化”中有专门提到过,而真正了解这个知识的人并不多,所以才有了如标题所说的结果~
OK,现在我们来开始一步步分析:首先加载class文件,对类中的变量进行内存分配(声明),此时instance是实例变量,加载的时候并不会对其进行真正的初始化(即不会把1赋给它,它只会得到系统给它的默认值0,这是问题的关键)。
接下来就要执行main方法体了,ok,它里面只有一条语句,new一个子类对象,调用子类默认构造器的时候要先调用父类的无参构造器,父类构造器这时会调用父类的test方法,根据多态原理,该test方法将会被子类的test覆盖,子类方法将会打印一条语句,而此时instance变量并未被初始化,故打印的结果为0.这里的this.test()方法调用可能不是很好理解,因为它已经用this表明调用父类方法,此时它是不知道子类已经覆盖了父类的这个方法,关于这一点,目前还找不到解释的方法,姑且把它理解为多态机制吧。
好了,现在我们把程序稍微改动一下,就是把private int instanceValue = 1;改为private static int instanceValue = 1;此时输出的结果就为1了,因为将instance声明为类变量后,在类被加载的时候就已经对其进行初始化了,关于这一点,在之前的帖子“类加载分为三个过程:装载、链接、初始化”有详细说明。
事实上这个源程序一点都不难,到为什么有那么多人会得出错误的结论呢,主要原因就是对原理机制不是很了解,而这个应该在我们以后的学习中引起足够的重视,现在很多公司笔试面试的时候都会涉及诸如这样的细节,所以从现在开始我们就要做好准备了,呵呵
public class Parent
{
protected void test() {}
public Parent()
{
this.test();
}
public static void main(String[] args)
{
new Child();
}
}
class Child extends Parent
{
private int instanceValue = 1;
public void test()
{
System.out.println("instance value is: " + instanceValue);
}
}
--------------------------------------------
此程序的输出结果为instance value is:0,可能很多人(包括很多老程序员)都会想当然得以为输出结果为1,或者不会有输出,或者认为这个程序本身就是错的(我的老师就是这么认为的,呵呵~)
看了很多有关这个问题的讨论,现在提出一点我的见解:
分析:这个问题首先涉及的知识是类加载分为三个过程:装载、链接、初始化,有关这个知识我在之前的帖子“类加载分为三个过程:装载、链接、初始化”中有专门提到过,而真正了解这个知识的人并不多,所以才有了如标题所说的结果~
OK,现在我们来开始一步步分析:首先加载class文件,对类中的变量进行内存分配(声明),此时instance是实例变量,加载的时候并不会对其进行真正的初始化(即不会把1赋给它,它只会得到系统给它的默认值0,这是问题的关键)。
接下来就要执行main方法体了,ok,它里面只有一条语句,new一个子类对象,调用子类默认构造器的时候要先调用父类的无参构造器,父类构造器这时会调用父类的test方法,根据多态原理,该test方法将会被子类的test覆盖,子类方法将会打印一条语句,而此时instance变量并未被初始化,故打印的结果为0.这里的this.test()方法调用可能不是很好理解,因为它已经用this表明调用父类方法,此时它是不知道子类已经覆盖了父类的这个方法,关于这一点,目前还找不到解释的方法,姑且把它理解为多态机制吧。
好了,现在我们把程序稍微改动一下,就是把private int instanceValue = 1;改为private static int instanceValue = 1;此时输出的结果就为1了,因为将instance声明为类变量后,在类被加载的时候就已经对其进行初始化了,关于这一点,在之前的帖子“类加载分为三个过程:装载、链接、初始化”有详细说明。
事实上这个源程序一点都不难,到为什么有那么多人会得出错误的结论呢,主要原因就是对原理机制不是很了解,而这个应该在我们以后的学习中引起足够的重视,现在很多公司笔试面试的时候都会涉及诸如这样的细节,所以从现在开始我们就要做好准备了,呵呵
相关文章推荐
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 透过现象看本质,一个Java多线程问题引出的思考
- 一个多数程序员都会犯的错:Java方法传参的问题
- 一个合格的程序员应具备的素质,喜欢思考,爱钻研,善于解决问题。
- 学习Java的第一步是安装好JDK,写一个Hello World, 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加
- .NET还是JAVA,这是一个值得思考的问题
- 关于Java继承一个值得思考的问题。
- .NET还是JAVA,这是一个值得思考的问题
- 一个问号引发的血案之程序员的职业素养(java.sql.SQLException: 无效的列索引问题)
- Java中一个运用反射解决问题例子+思考
- (转)专业的程序员需要具备的思考能力:写一个程序需要注意多少细节问题
- Java程序员应该常思考的问题
- 一个JDK版本问题引发的思考--Java环境配置 && Eclipse的JDK配置
- 专业的程序员需要具备的思考能力:写一个程序需要注意多少细节问题
- java程序员应该思考的问题