Skip to content

第7课:继承

🎯 学习目标

  • 理解继承的概念和作用
  • 掌握 extends 关键字
  • 理解 super 关键字
  • 掌握方法重写
  • 理解 Object 类

📖 一、继承基础

C vs Java 继承

C 语言

c
// C: 无继承,需手动组合
struct Animal {
    char name[50];
};

struct Dog {
    struct Animal animal;  // 组合
    char breed[50];
};

Java

java
// Java: 原生支持继承
class Animal {
    String name;
}

class Dog extends Animal {
    String breed;
}

1. 继承语法

java
// 父类(超类、基类)
public class Animal {
    String name;
    int age;
    
    public void eat() {
        System.out.println(name + " is eating");
    }
}

// 子类(派生类)
public class Dog extends Animal {
    String breed;
    
    public void bark() {
        System.out.println(name + " is barking");
    }
}

// 使用
Dog dog = new Dog();
dog.name = "旺财";    // 继承自 Animal
dog.age = 3;         // 继承自 Animal
dog.breed = "哈士奇"; // Dog 自己的属性
dog.eat();           // 继承的方法
dog.bark();          // Dog 自己的方法

2. 继承的特点

  • ✅ 子类继承父类的所有非 private 成员
  • ✅ Java 只支持单继承(一个类只能有一个直接父类)
  • ✅ 支持多层继承(A → B → C)
  • ❌ 不支持多重继承(C++ 支持)
java
// ✅ 单继承
class A { }
class B extends A { }

// ✅ 多层继承
class C extends B { }

// ❌ 多重继承(编译错误)
class D extends A, B { }  // 错误

📖 二、super 关键字

1. 访问父类成员

java
public class Animal {
    String name = "动物";
    
    public void eat() {
        System.out.println("Animal eating");
    }
}

public class Dog extends Animal {
    String name = "狗";
    
    public void printName() {
        System.out.println(name);        // 狗(子类的)
        System.out.println(super.name);  // 动物(父类的)
    }
    
    public void eat() {
        super.eat();  // 调用父类方法
        System.out.println("Dog eating");
    }
}

2. 调用父类构造方法

java
public class Animal {
    String name;
    int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Dog extends Animal {
    String breed;
    
    public Dog(String name, int age, String breed) {
        super(name, age);  // 调用父类构造方法(必须是第一条语句)
        this.breed = breed;
    }
}

⚠️ 注意

  • super() 必须是构造方法的第一条语句
  • 如果不写,编译器自动调用 super()(无参构造)
  • 如果父类没有无参构造,子类必须显式调用有参构造
java
public class Animal {
    public Animal(String name) {  // 只有有参构造
    }
}

public class Dog extends Animal {
    public Dog() {
        // super();  // ❌ 错误:父类没有无参构造
        super("Dog");  // ✅ 正确
    }
}

📖 三、方法重写(Override)

1. 重写规则

java
public class Animal {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

public class Dog extends Animal {
    @Override  // 可选注解,编译时检查
    public void makeSound() {
        System.out.println("Woof!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow!");
    }
}

// 使用
Animal dog = new Dog();
dog.makeSound();  // Woof!(调用子类的方法)

Animal cat = new Cat();
cat.makeSound();  // Meow!

2. 重写的要求

  • ✅ 方法名相同
  • ✅ 参数列表相同
  • ✅ 返回类型相同(或子类)
  • ✅ 访问权限不能更严格
  • ❌ 不能重写 private、static、final 方法
java
public class Parent {
    public void method() { }
}

public class Child extends Parent {
    // ✅ 正确:访问权限相同
    public void method() { }
    
    // ❌ 错误:访问权限更严格
    // protected void method() { }
}

3. 重写 vs 重载

特性重写(Override)重载(Overload)
关系父类和子类同一个类
方法名相同相同
参数列表相同不同
返回类型相同可以不同
访问修饰符不能更严格无要求

📖 四、Object 类

1. Object 类简介

  • Java 中所有类的根父类
  • 如果没有 extends,默认继承 Object
  • 提供了通用方法
java
public class MyClass {  }
// 等价于
public class MyClass extends Object {  }

2. Object 类的常用方法

java
public class Object {
    // 返回对象的字符串表示
    public String toString() { }
    
    // 比较两个对象是否相等
    public boolean equals(Object obj) { }
    
    // 返回哈希码
    public int hashCode() { }
    
    // 返回 Class 对象
    public final Class<?> getClass() { }
    
    // 克隆对象
    protected Object clone() { }
}

3. 重写 toString()

java
public class Person {
    String name;
    int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 不重写时
    // Person p = new Person("Alice", 25);
    // System.out.println(p);  // Person@15db9742(默认格式)
    
    // 重写后
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

// 使用
Person p = new Person("Alice", 25);
System.out.println(p);  // Person{name='Alice', age=25}

4. 重写 equals()

java
public class Person {
    String name;
    int age;
    
    @Override
    public boolean equals(Object obj) {
        // 1. 检查是否是同一个对象
        if (this == obj) return true;
        
        // 2. 检查是否为 null 或类型不同
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        
        // 3. 比较属性
        Person person = (Person) obj;
        return age == person.age && 
               name.equals(person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

📖 五、访问控制

修饰符同一类同一包子类任意位置
private
默认
protected
public
java
public class Parent {
    private int a = 1;      // 子类不可访问
    int b = 2;              // 同包子类可访问
    protected int c = 3;    // 子类可访问
    public int d = 4;       // 都可访问
}

public class Child extends Parent {
    public void test() {
        // System.out.println(a);  // ❌ 错误
        System.out.println(b);     // ✅ 同包
        System.out.println(c);     // ✅ protected
        System.out.println(d);     // ✅ public
    }
}

⚠️ 常见陷阱

陷阱1:为了复用代码而滥用继承

继承表达“is-a”关系,不应只为了复用几行代码。很多场景组合比继承更稳。

陷阱2:重写方法破坏父类约定

子类重写方法必须遵守父类方法的语义,否则多态调用会出现意外行为。

陷阱3:忘记调用 super

构造器、初始化逻辑或重写方法中,如果父类有必要逻辑,需要显式调用 super

陷阱4:protected 滥用

protected 不是“更安全的 public”。暴露给子类的成员也会形成长期兼容负担。


🆚 Java vs C 对比

特性CJava 继承
继承无语言级继承单继承
多态函数指针模拟虚方法动态绑定
基类无统一根类型Object
复用方式组合 struct + 函数继承、组合、接口

对 C 程序员来说,Java 继承像编译器和运行时内置的“结构体嵌套 + 虚函数表”机制,但更强调类型关系和多态契约。


💡 最佳实践

1. 遵循 IS-A 关系

java
// ✅ Dog IS-A Animal(狗是一种动物)
class Dog extends Animal { }

// ❌ Car IS-A Engine?(车不是引擎,应该用组合)
class Car {
    Engine engine;  // 组合
}

2. 不要为了复用而继承

java
// ❌ 不好:为了复用 Stack 的方法
class MyList extends Stack { }

// ✅ 好:组合
class MyList {
    private Stack stack = new Stack();
}

3. 父类应该是抽象的概念

java
// ✅ 好
class Animal { }  // 抽象概念
class Dog extends Animal { }

// ❌ 不好
class Dog { }
class Husky extends Dog { }  // 太具体了

📝 练习

完成 练习/Ex07_Inheritance.java

  1. 继承基本使用
  2. super 关键字
  3. 方法重写
  4. Object 类方法
  5. 访问控制
  6. 综合:员工管理系统

🎓 下一步

  • 第8课:多态 - 向上转型、向下转型、动态绑定