继承是 Java 面向对象编程的核心特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用、简化开发并建立类之间的层次关系。在继承关系中,构造方法的调用逻辑与普通方法不同,需要遵循特定规则。掌握继承的实现方式和构造方法的调用机制,是理解类层级设计的基础。
一、Java 继承的实现方式
(一)继承的基本语法
Java 通过extends关键字实现继承,语法格式为:
修饰符 class 子类名 extends 父类名 {...}
其中,子类(派生类)会自动获得父类(基类)中非私有的成员变量和方法,同时可以定义自己的独有属性和方法,实现功能扩展。
示例:定义父类Person和子类Student
// 父类:描述人的共性class Person { String name; int age; void eat() { System.out.println(name + "正在吃饭"); }}// 子类:继承Person,增加学生特有的属性和方法class Student extends Person { String studentId; // 独有属性:学号 // 独有方法:学习 void study() { System.out.println(name + "(学号:" + studentId + ")正在学习"); }}
子类Student继承了Person的name、age变量和eat()方法,同时新增了studentId变量和study()方法,实现了 “学生是特殊的人” 这一逻辑关系。
(二)继承的特性
单继承限制:Java 中一个子类只能直接继承一个父类(单继承),避免多继承导致的逻辑混乱,但可通过多层继承实现功能传递(如Student extends Person,Graduate extends Student)。
访问权限控制:父类的private成员(变量或方法)对子类不可见,public和protected成员可被继承,默认修饰符(同包可见)在同包子类中可访问。
方法重写(Override):子类可重写父类的方法,修改其实现逻辑,需保证方法名、参数列表和返回值类型与父类一致。
示例:重写Person类的eat()方法
class Student extends Person { // 重写父类方法 @Override void eat() { System.out.println(name + "在学校食堂吃饭"); }}
二、继承中构造方法的调用规则
构造方法用于对象初始化,在继承关系中,子类构造方法的调用会触发父类构造方法的执行,遵循 “先初始化父类,再初始化子类” 的原则。
(一)默认调用父类无参构造方法
若子类构造方法中未显式调用父类构造方法,Java 会自动隐式调用父类的无参构造方法,确保父类成员先初始化。
示例:隐式调用父类构造方法
class Person { // 父类无参构造方法 Person() { System.out.println("Person无参构造方法被调用"); }}class Student extends Person { // 子类构造方法 Student() { // 隐式调用super(),即父类无参构造方法 System.out.println("Student无参构造方法被调用"); }}// 测试public class Test { public static void main(String[] args) { Student stu = new Student(); // 输出顺序: // Person无参构造方法被调用 // Student无参构造方法被调用 }}
(二)显式调用父类构造方法(super())
若父类没有无参构造方法(如仅定义了有参构造),子类必须在构造方法的第一行通过super(参数)显式调用父类的有参构造方法,否则编译报错。
示例:显式调用父类有参构造
class Person { String name; // 父类仅定义有参构造,无默认无参构造 Person(String name) { this.name = name; System.out.println("Person有参构造方法被调用,姓名:" + name); }}class Student extends Person { String studentId; // 子类构造方法必须显式调用父类有参构造 Student(String name, String id) { super(name); // 第一行调用父类构造,传递name参数 this.studentId = id; System.out.println("Student有参构造方法被调用,学号:" + id); }}// 测试public class Test { public static void main(String[] args) { Student stu = new Student("张三", "2023001"); // 输出顺序: // Person有参构造方法被调用,姓名:张三 // Student有参构造方法被调用,学号:2023001 }}
(三)构造方法调用的注意事项
super()必须放在子类构造方法的第一行,否则无法通过编译,这是为了保证父类初始化先于子类。
若父类既无无参构造也无有参构造(仅默认构造),子类可隐式调用;若父类自定义了构造方法,默认无参构造会失效,需显式定义或在子类中显式调用有参构造。
子类构造方法中不能同时调用super()和this()(子类其他构造方法),两者均需放在第一行,存在冲突。
三、继承的典型应用场景
代码复用:将多个类的共性属性和方法提取到父类,减少重复代码。例如,Student和Teacher都继承Person类,共享name、age等属性。
功能扩展:子类在继承父类的基础上新增特性,如VIPUser继承User类,增加discount(折扣)属性和getVipService()方法。
多态实现:基于继承的方法重写是多态的基础,如父类引用指向子类对象(Person p = new Student()),调用方法时会执行子类重写的实现。
四、继承使用的注意事项
避免过度继承:多层继承可能导致类层级复杂,难以维护,建议继承层级不超过 3 层。
符合逻辑关系:继承应遵循 “is-a” 原则(子类是父类的一种),如Cat extends Animal(猫是动物)合理,Book extends Person(书是人)则不符合逻辑。
谨慎使用protected:父类protected成员可被子类访问,若过度使用可能破坏封装性,建议通过getter/setter方法控制访问。
Java 继承通过extends关键字实现类的层级关系,核心价值是代码复用与扩展;而构造方法的调用遵循 “父类优先” 原则,需注意显式与隐式调用的场景。掌握这些知识,能帮助开发者设计更清晰、更灵活的类结构,为理解多态、抽象类等高级特性奠定基础。