thunderzhulei的专栏

一个在java中游泳的scjp

java对象创建过程

凡是用过面向对象语言的人都写过构造函数(废话一句),java程序员更是如此。由于java是纯面向对象的语言,所以可能造成构造函数满天飞的情况....但是,你知道,当执行构造函数的时候,这短短的一句在JVM中都做了什么吗?

看下面一段代码

class A{
 public int varA;
 public A(){
  System.out.println("inside A");
  getVar();
 }
 public void getVar(){
  varA = 321;
  System.out.println("varA = " + varA);
 }
}
public class B extends A{
 public int varB = 123;
 public B(){
  System.out.println("inside B");
  getVar();
  System.out.println("varA = " + varA);
 }
 public void getVar(){
  System.out.println("varB = " + varB);
 }

 public static void main(String[] args){
  new B();
 }
}

奇怪吧,下面解释一下调用new B()时到底发生了什么

奇怪吧,下面解释一下调用new B()时到底发生了什么
  1. 当然是调用B的构造函数了
  2. 由于B是从A继承而来,会默认的调用A的无参构造函数。这里注意,如果A没有提供默认构造函数,而是提供了有参的构造函数,编译将会出错
  3. 初始化A中的实例变量。由于varA没有在声明时赋值,JVM会将它初始化为0。此时,还没有执行A构造函数中的代码。
  4. 执行System.out.println("inside A"),输出第一行。然后调用getVar()。这里可以花时间解释一下为什么输出的是varB而不是varA。getVar()是覆盖方法。在java中,覆盖方法是动态决定的,也就是根据拥有它的对象类型来执行,而不是根据引用类型来决定。这一点正好和重载方法相反。因此,这里会执行联编后B的getVar(),而此时varB还没有初始化,所以默认为0
  5. 执行到这里,A类构造函数的内容已经完毕,返回B的构造函数,执行System.out.println("inside B")
  6. 此时继续执行getVar(),这时也是执行B的方法,由于varB在声明时已经显示初始化,故输出varB = 123
  7. 执行System.out.println("varA = " + varA)。从前面可以看出,A类的getVar()根本没有执行,所以varA一直没有被赋值,所以它的值还是0

没想到吧,一句短短的new B()可以引起这么多的调用。其实,如果涉及到静态域或变量,情况要比上面复杂的多,有兴趣的朋友可以试验一下

总结一下,关于调用构造函数创建一个类的过程如下

  1. 调用构造函数
  2. 初始化该类的静态变量
  3. 初始化该类的静态块(static block)
  4. 调用该类构造函数的第一句(super或this)。如果没有写出,默认调用super()
  5. 初始化变量/执行语句块
  6. 执行构造函数剩下的内容
阅读更多
个人分类: java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭