Skip to content

11.2 继承(extends)

继承的概念

继承(Inheritance)是面向对象编程的三大特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用。

继承的语法

语法:

java
public class 子类名 extends 父类名 {
    // 子类的属性和方法
}

示例:

java
// 父类
public class Person {
    private String name;
    private int age;
    
    // 构造方法、getter 和 setter 方法
}

// 子类
public class Student extends Person {
    private int studentId;
    private double grade;
    
    // 构造方法、getter 和 setter 方法
}

继承的特点

  1. 单继承:Java 支持单继承,一个子类只能继承一个父类
  2. 多层继承:Java 支持多层继承,一个子类可以继承一个父类,而这个父类又可以继承另一个父类
  3. 继承的内容:子类继承父类的非私有属性和方法
  4. 方法重写:子类可以重写父类的方法,实现自己的逻辑
  5. super 关键字:子类可以使用 super 关键字访问父类的属性和方法

示例:继承的基本使用

示例 1:学生类继承人类

java
// 父类:Person
public class Person {
    private String name;
    private int age;
    
    // 构造方法
    public Person() {
    }
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // getter 和 setter 方法
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    // 方法
    public void eat() {
        System.out.println(name + " is eating.");
    }
    
    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

// 子类:Student
public class Student extends Person {
    private int studentId;
    private double grade;
    
    // 构造方法
    public Student() {
    }
    
    public Student(String name, int age, int studentId, double grade) {
        super(name, age); // 调用父类的构造方法
        this.studentId = studentId;
        this.grade = grade;
    }
    
    // getter 和 setter 方法
    public int getStudentId() {
        return studentId;
    }
    
    public void setStudentId(int studentId) {
        this.studentId = studentId;
    }
    
    public double getGrade() {
        return grade;
    }
    
    public void setGrade(double grade) {
        this.grade = grade;
    }
    
    // 方法
    public void study() {
        System.out.println(getName() + " is studying.");
    }
    
    public boolean isPass() {
        return grade >= 60;
    }
}

// 测试类
public class StudentExample {
    public static void main(String[] args) {
        // 创建学生对象
        Student student = new Student("John", 18, 1001, 85.5);
        
        // 调用继承自父类的方法
        student.eat();
        student.sleep();
        
        // 调用子类自己的方法
        student.study();
        System.out.println(student.getName() + " is pass: " + student.isPass());
        
        // 使用 getter 和 setter 方法
        student.setName("Jane");
        student.setAge(19);
        student.setGrade(92.0);
        
        System.out.println("Name: " + student.getName());
        System.out.println("Age: " + student.getAge());
        System.out.println("Student ID: " + student.getStudentId());
        System.out.println("Grade: " + student.getGrade());
    }
}

示例 2:多层继承

java
// 父类:Person
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void eat() {
        System.out.println(name + " is eating.");
    }
}

// 子类:Student,继承自 Person
public class Student extends Person {
    private int studentId;
    
    public Student(String name, int age, int studentId) {
        super(name, age);
        this.studentId = studentId;
    }
    
    public int getStudentId() {
        return studentId;
    }
    
    public void study() {
        System.out.println(getName() + " is studying.");
    }
}

// 子类:GraduateStudent,继承自 Student
public class GraduateStudent extends Student {
    private String major;
    
    public GraduateStudent(String name, int age, int studentId, String major) {
        super(name, age, studentId);
        this.major = major;
    }
    
    public String getMajor() {
        return major;
    }
    
    public void research() {
        System.out.println(getName() + " is researching in " + major + ".");
    }
}

// 测试类
public class GraduateStudentExample {
    public static void main(String[] args) {
        // 创建研究生对象
        GraduateStudent graduateStudent = new GraduateStudent("John", 22, 2001, "Computer Science");
        
        // 调用继承自 Person 的方法
        graduateStudent.eat();
        
        // 调用继承自 Student 的方法
        graduateStudent.study();
        
        // 调用自己的方法
        graduateStudent.research();
        
        // 使用 getter 方法
        System.out.println("Name: " + graduateStudent.getName());
        System.out.println("Age: " + graduateStudent.getAge());
        System.out.println("Student ID: " + graduateStudent.getStudentId());
        System.out.println("Major: " + graduateStudent.getMajor());
    }
}

示例 3:方法重写

java
// 父类:Animal
public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound.");
    }
    
    public void eat() {
        System.out.println("Animal eats.");
    }
}

// 子类:Dog
public class Dog extends Animal {
    // 重写父类的方法
    @Override
    public void makeSound() {
        System.out.println("Dog barks.");
    }
    
    // 继承父类的方法,不重写
    // public void eat() { ... }
}

// 子类:Cat
public class Cat extends Animal {
    // 重写父类的方法
    @Override
    public void makeSound() {
        System.out.println("Cat meows.");
    }
    
    // 重写父类的方法
    @Override
    public void eat() {
        System.out.println("Cat eats fish.");
    }
}

// 测试类
public class AnimalExample {
    public static void main(String[] args) {
        // 创建动物对象
        Animal animal = new Animal();
        animal.makeSound();
        animal.eat();
        
        // 创建狗对象
        Dog dog = new Dog();
        dog.makeSound(); // 调用重写的方法
        dog.eat(); // 调用继承的方法
        
        // 创建猫对象
        Cat cat = new Cat();
        cat.makeSound(); // 调用重写的方法
        cat.eat(); // 调用重写的方法
    }
}

继承的优势

  1. 代码复用:子类可以继承父类的属性和方法,避免重复代码
  2. 扩展性:子类可以在父类的基础上扩展功能
  3. 维护性:修改父类的代码,所有子类都会受益
  4. 多态:通过继承,可以实现多态

继承的最佳实践

  1. 合理设计继承层次:避免过深的继承层次,一般不超过 3-4 层
  2. 遵循里氏替换原则:子类应该能够替换父类,而不影响程序的正确性
  3. 使用抽象类和接口:对于共同的行为,使用抽象类或接口
  4. 避免过度继承:只在真正需要继承的情况下使用继承
  5. 正确使用 super 关键字:在子类中使用 super 关键字访问父类的属性和方法

示例:合理的继承设计

java
// 抽象类:Shape
public abstract class Shape {
    public abstract double calculateArea();
    public abstract double calculatePerimeter();
}

// 子类:Circle
public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double calculatePerimeter() {
        return 2 * Math.PI * radius;
    }
}

// 子类:Rectangle
public class Rectangle extends Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double calculateArea() {
        return width * height;
    }
    
    @Override
    public double calculatePerimeter() {
        return 2 * (width + height);
    }
}

// 测试类
public class ShapeExample {
    public static void main(String[] args) {
        // 创建圆形对象
        Shape circle = new Circle(5);
        System.out.println("Circle area: " + circle.calculateArea());
        System.out.println("Circle perimeter: " + circle.calculatePerimeter());
        
        // 创建矩形对象
        Shape rectangle = new Rectangle(4, 6);
        System.out.println("Rectangle area: " + rectangle.calculateArea());
        System.out.println("Rectangle perimeter: " + rectangle.calculatePerimeter());
    }
}

常见问题

1. 构造方法的调用

症状:子类构造方法中没有调用父类的构造方法

解决方案:在子类构造方法中使用 super() 调用父类的构造方法

示例:

java
public class Parent {
    public Parent() {
        System.out.println("Parent constructor");
    }
}

public class Child extends Parent {
    public Child() {
        super(); // 调用父类的构造方法
        System.out.println("Child constructor");
    }
}

2. 方法重写错误

症状:子类重写父类方法时,方法签名不匹配

解决方案:确保子类重写的方法与父类方法的签名完全相同

示例:

java
public class Parent {
    public void method(int x) {
    }
}

public class Child extends Parent {
    // 错误:方法签名不匹配
    public void method(double x) {
    }
    
    // 正确:方法签名匹配
    @Override
    public void method(int x) {
    }
}

3. 访问权限问题

症状:子类无法访问父类的私有属性和方法

解决方案:将父类的属性和方法设置为 protected 或 public,或者提供公共的 getter 和 setter 方法

示例:

java
public class Parent {
    private int privateField; // 私有属性,子类无法访问
    protected int protectedField; // 受保护属性,子类可以访问
    
    private void privateMethod() { // 私有方法,子类无法访问
    }
    
    protected void protectedMethod() { // 受保护方法,子类可以访问
    }
}

public class Child extends Parent {
    public void accessParentMembers() {
        // 错误:无法访问私有属性
        // privateField = 10;
        
        // 正确:可以访问受保护属性
        protectedField = 10;
        
        // 错误:无法访问私有方法
        // privateMethod();
        
        // 正确:可以访问受保护方法
        protectedMethod();
    }
}

4. 继承层次过深

症状:继承层次过深,导致代码难以理解和维护

解决方案:减少继承层次,使用组合代替继承

示例:

java
// 过深的继承层次
public class A {
}

public class B extends A {
}

public class C extends B {
}

public class D extends C {
}

// 更好的设计:使用组合
public class A {
}

public class B {
    private A a;
}

public class C {
    private B b;
}

总结

继承是面向对象编程的三大特性之一,它允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用。

继承的特点:

  • 单继承:一个子类只能继承一个父类
  • 多层继承:支持多层继承
  • 继承的内容:子类继承父类的非私有属性和方法
  • 方法重写:子类可以重写父类的方法
  • super 关键字:子类可以使用 super 关键字访问父类的属性和方法

继承的优势:

  • 代码复用:避免重复代码
  • 扩展性:在父类的基础上扩展功能
  • 维护性:修改父类的代码,所有子类都会受益
  • 多态:通过继承,可以实现多态

通过合理使用继承,可以使代码更加简洁、可维护和可扩展。

© 2026 编程马·菜鸟教程 版权所有