当实例化一个继承自抽象类的子类时,Java会调用父类的构造函数,并根据继承链进行初始化。这包括父类的字段初始化、初始化块和构造函数。父类中的方法(包括被子类重写的方法)也可能会在这个过程中被调用。以下是详细分析及代码示例。
详细分析
-
调用父类构造函数:
- 在实例化子类时,首先调用父类的构造函数。
- 父类构造函数的调用是由子类构造函数中的
super()
显式或隐式调用。
-
初始化父类字段和代码块:
- 在调用父类构造函数之前,父类中的字段和初始化块会被执行。
-
调用父类方法:
- 父类的构造函数和初始化块可以调用父类的方法。如果这些方法在子类中被重写,则在这些调用中会执行子类重写的方法。
示例代码
父类(抽象类)
abstract class Parent {
String name;
{
System.out.println("Parent initialization block");
}
public Parent(String name) {
this.name = name;
System.out.println("Parent constructor called with name: " + name);
this.init();
}
protected abstract void init();
public void showName() {
System.out.println("Name: " + name);
}
}
子类
class Child extends Parent {
String childName;
{
System.out.println("Child initialization block");
}
public Child(String name, String childName) {
super(name);
this.childName = childName;
System.out.println("Child constructor called with childName: " + childName);
}
@Override
protected void init() {
System.out.println("Child init method called");
}
@Override
public String toString() {
return "Child{name='" + name + "', childName='" + childName + "'}";
}
}
测试类
public class MainClass {
public static void main(String[] args) {
System.out.println("Main method start");
Child child = new Child("ParentName", "ChildName");
System.out.println("Child instance: " + child);
child.showName();
}
}
输出分析
运行上述代码,输出如下:
Main method start
Parent initialization block
Parent constructor called with name: ParentName
Child init method called
Child initialization block
Child constructor called with childName: ChildName
Child instance: Child{name='ParentName', childName='ChildName'}
Name: ParentName
调用顺序和输出说明
-
父类字段初始化和代码块:
- 父类的字段初始化和初始化块在父类构造函数之前执行。
- 输出:“Parent initialization block”
-
父类构造函数:
- 父类构造函数
Parent(String name)
被调用,并打印:- 输出:“Parent constructor called with name: ParentName”
- 在父类构造函数中调用
this.init()
方法,由于init
方法在子类中被重写,因此调用的是子类的init
方法:- 输出:“Child init method called”
- 父类构造函数
-
子类字段初始化和代码块:
- 子类的字段初始化和初始化块在子类构造函数之前执行。
- 输出:“Child initialization block”
-
子类构造函数:
- 子类构造函数
Child(String name, String childName)
被调用,并打印:- 输出:“Child constructor called with childName: ChildName”
- 子类构造函数
-
调用
toString()
方法:- 当打印
child
对象时,调用子类重写的toString()
方法,返回对象的字符串表示:- 输出:“Child instance: Child{name=‘ParentName’, childName=‘ChildName’}”
- 当打印
-
调用
showName()
方法:- 调用父类的方法
showName()
,打印:- 输出:“Name: ParentName”
- 调用父类的方法
总结
在实例化子类时,会依次调用父类的初始化块、构造函数、以及父类构造函数中可能调用的方法。如果这些方法在子类中被重写,则会执行子类的方法。通过正确设计和调用,可以确保类在实例化时的正确初始化和方法调用。