第28章

Java继承

掌握类的继承和extends关键字的使用方法与最佳实践

学习目标

Java继承概念详解

继承是面向对象编程的核心特性之一,它允许一个类(子类)获得另一个类(父类)的属性和方法。通过继承,我们可以实现代码复用、扩展功能和建立类之间的层次关系。

extends关键字

语法示例:
public class Dog extends Animal {
    // Dog类继承了Animal类的所有非私有成员
}
  • 建立继承关系的关键字
  • 子类获得父类的属性和方法
  • Java只支持单继承
  • 所有类都隐式继承Object类

方法重写(Override)

语法示例:
@Override
public void makeSound() {
    System.out.println("汪汪汪!");
}
  • 子类重新定义父类的方法
  • 使用@Override注解标记
  • 方法签名必须完全相同
  • 实现多态性的基础

super关键字

语法示例:
public Dog(String name, int age) {
    super(name, age, "犬科");
    // 调用父类构造方法
}
  • 访问父类的成员
  • 调用父类的构造方法
  • 调用父类被重写的方法
  • 解决命名冲突

继承的特性和规则

访问修饰符在继承中的作用

不同的访问修饰符决定了子类对父类成员的访问权限:

修饰符 同一类 同一包 子类 其他包
public
protected
default
private
重要提示:protected修饰符是专门为继承设计的,它允许子类访问父类的成员,但不允许其他包中的非子类访问。

构造方法调用顺序

在继承关系中,构造方法的调用遵循特定的顺序:

构造方法调用示例:
public class Animal {
    public Animal() {
        System.out.println("Animal构造方法被调用");
    }
}

public class Dog extends Animal {
    public Dog() {
        super(); // 隐式调用,可以省略
        System.out.println("Dog构造方法被调用");
    }
}

// 创建Dog对象时的输出:
// Animal构造方法被调用
// Dog构造方法被调用
注意:如果父类没有无参构造方法,子类必须在构造方法的第一行显式调用父类的有参构造方法。

继承实战示例

让我们通过一个完整的动物继承体系来理解继承的实际应用:

父类 - Animal.java:
public class Animal {
    protected String name;
    protected int age;
    protected String species;
    
    public Animal(String name, int age, String species) {
        this.name = name;
        this.age = age;
        this.species = species;
    }
    
    public void eat() {
        System.out.println(name + "正在吃东西...");
    }
    
    public void makeSound() {
        System.out.println(name + "发出了声音");
    }
    
    public String getInfo() {
        return String.format("动物信息: 名称=%s, 年龄=%d岁, 种类=%s", 
                           name, age, species);
    }
}
子类 - Dog.java:
public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, int age, String breed) {
        super(name, age, "犬科"); // 调用父类构造方法
        this.breed = breed;
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + "汪汪汪!");
    }
    
    @Override
    public void eat() {
        System.out.println(name + "正在吃狗粮,摇着尾巴很开心!");
    }
    
    // 子类特有的方法
    public void wagTail() {
        System.out.println(name + "开心地摇尾巴!");
    }
    
    @Override
    public String getInfo() {
        return super.getInfo() + ", 品种=" + breed;
    }
}
💻 查看完整代码 - 在线IDE体验

继承的最佳实践

继承设计原则

推荐做法

  • 使用"is-a"关系判断是否适合继承
  • 父类设计要考虑扩展性
  • 使用protected修饰符允许子类访问
  • 重写方法时使用@Override注解
  • 在子类构造方法中调用super()
  • 遵循里氏替换原则

避免做法

  • 为了代码复用而强行使用继承
  • 继承层次过深(超过3-4层)
  • 在父类中使用子类特有的方法
  • 重写方法时改变原有的语义
  • 在构造方法中调用可重写的方法
  • 违反开闭原则修改父类
设计建议:优先考虑组合而不是继承。只有在确实存在"is-a"关系时才使用继承,否则考虑使用组合或接口。

章节总结