构造函数不继承,但不显示调用时有默认调用

  • 继承时构造函数的特点
  • 子类的实例化过程


继承时构造函数的特点

  • 在子类构造对象中,第一行有一个隐式的语句:super();//调用的就是父类中的空参数的构造函数。
  • 如果父类中没有定义默认的无参构造函数,那么在子类中需要通过super明确指定父类的构造函数

子类的实例化过程

  • 子类的所有构造函数中,都会默认访问父类的无参构造函数super();
  • 如果使用有参构造函数,则需要puper(…);指定
  • 子类实例化的过程中,必须要访问父类中的构造函数(因为子类继承了父类,获取到了父类中的属性,所以在使用父类中的内容时,先要对父类中的内容进行初始化。)
  • super语句必须要定义在子类构造函数的第一行。(因为父类的初始化动作需要先完成)
  • 在子类中某个构造函数中,使用this();时,那么super就没有了,因为super和this都只能定义在第一行。但是必须确定的是,子类中比如有其他的构造函数访问父类中的构造函数。
class Parent{
	
	Parent(){
		System.out.println("Parent run");
		show();
	}
	
	void show(){
		System.out.println("Parent show");
	}
}

class ChildTest extends Parent{
	int num=10;
	
	ChildTest(){
		System.out.println("child run");
		show();
	}
	
	void show(){
		System.out.println("child show num="+num);
	}
	
	public static void main(String[] args){
		new ChildTest();
	}
	
}

构造函数初始化eg2

//父类
class Parent {
    //父类构造函数
    Parent() {
        print();
    }
    //父类方法
    void print() {
        System.out.println("print parent");
    }
}

class Child extends Parent {
    int x = 10;

    Child() {
        //super();这里有一句默认的
        //在父类的构造函数中调用了print()方法,但是该方法已经被子类覆盖
        //所以调用了子类的print方法 所以第一次打印的内容为:child show x=0
        //完成了父类的初始化之后,紧接着初始化子类的显示初始化内容,于是在这里x=10
        System.out.println("child constructor x=" + x);
        //所以这里打印的内容为:child constructor x=10
    }

    //覆盖了父类的方法
    void print() {
        System.out.println("child show x=" + x);
    }
}

class Test {
    public static void main(String[] args) {
        new Child();
    }
}

运行结果为

Parent run
child show num=0
child run
child show num=10

结果分析:在new ChildTest()时;

  1. 分配堆内存空间,其中有一个整数num 初始化时默认为num=0;
  2. 默认第一句为super();
  3. 所以调用了Parent();
  4. 在Parent()中打印了"Parent run"
  5. 打印后调用了show();show()被ChildTest中的show覆盖,所以调用了子类的show,而此时的num=0;所以开始第二句打印:child show num=0
  6. 父类构造函数调用完毕,开始初始化子类显示初始化,此时num=10,并开始了子类构造函数打印:child run
  7. 调用show();show()函数被子类覆盖,所以调用的依然是子类的show(),于是打印的结果为:child show num=10
  • 一个对象初始化过程
  • new ChildTest
  1. JVM读取classpath下的ChildTest.class 文件,并加载进方法区内存。
    并先加载父类Parent.class.
  2. 在堆内存中分配内存空间,分配内存地址。
  3. 在对象空间中,对对象中的属性进行默认初始化。
  4. 调用对应的构造函数进行初始化。
  5. 在构造函数中,第一行会先调用父类中的构造函数进行初始。
  6. 父类初始化完毕之后,再对子类的属性进行显示初始化。
  7. 再进行子类构造函数的初始化。
  8. 初始化完毕后,将地址赋值给引用变量。
  • 类初始化过程
  1. 分配空间
  2. super();调用父类的构造函数
  3. 显示初始化
  4. 构造代码块初始化
  5. 构造函数初始化