Skip to content

2026-08-27 · 子类复用父类的属性和方法——代码复用的核心机制。

Java 继承

1. 继承基础

extends 关键字,子类继承父类的属性和方法:

java
// 父类
public class Animal {
    String name;
    int age;

    public void eat() {
        System.out.println(name + " 在吃东西");
    }

    public void sleep() {
        System.out.println(name + " 在睡觉");
    }
}

// 子类
public class Dog extends Animal {
    String breed;  // 子类特有的属性

    public void bark() { // 子类特有的方法
        System.out.println(name + " 在汪汪叫");
    }
}

// 使用
Dog dog = new Dog();
dog.name = "旺财";    // ✅ 继承了父类的属性
dog.breed = "金毛";
dog.eat();            // ✅ 继承了父类的方法
dog.bark();           // ✅ 子类特有方法

继承规则

  • Java 只支持单继承(一个子类只能有一个父类)
  • 可以多层继承(A → B → C)
  • 子类可以有自己的属性和方法

多层继承(A → B → C)尽量少用,层级太深会很复杂。一般不超过两层。

2. 继承中的变量

子类和父类有同名变量时:

java
public class Parent {
    String name = "父类";
}

public class Child extends Parent {
    String name = "子类";

    public void print() {
        System.out.println(name);  // 子类
    }
}

Child c = new Child();
c.print(); // 子类(就近原则:优先用子类自己的)

变量访问顺序(就近原则):

  1. 当前类(局部变量 → 成员变量 → 父类成员变量)
  2. 父类
  3. 父父类(以此类推)

变量不存在重写(override),只有重名遮蔽。子类和父类的 name 是两个独立的变量,互不影响。

3. 继承中的方法

子类可以重写父类的方法(方法重写 Override):

java
public class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

public class Dog extends Animal {
    @Override  // 注解,告诉编译器这是重写,不是新方法
    public void makeSound() {
        System.out.println("汪汪汪!");
    }
}

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

Dog dog = new Dog();
Cat cat = new Cat();
dog.makeSound(); // 汪汪汪!
cat.makeSound(); // 喵喵喵!

方法重写规则

  • 方法名必须相同
  • 参数列表必须相同
  • 返回值类型必须相同(或协变,子类返回值可以是父类返回值的子类型)
  • 修饰符不能更严格(父类是 public,子类不能是 private
  • 不能抛出更多/更大的受检异常
java
// ✅ 合法重写
public class Parent {
    public String get() { return ""; }
}

public class Child extends Parent {
    @Override
    public String get() { return "child"; } // 返回值类型相同
}

// ❌ 不合法(返回值类型不同)
public class Child extends Parent {
    @Override
    public int get() { return 0; } // 编译报错
}

@Override 不是必须的,但强烈建议加上。它能让编译器帮你检查是否正确重写了。

4. super 与 this

java
public class Parent {
    String name = "父类";

    public Parent() {
        System.out.println("父类无参构造");
    }

    public Parent(String name) {
        System.out.println("父类有参构造:" + name);
    }

    public void show() {
        System.out.println("父类方法:" + name);
    }
}

public class Child extends Parent {
    String name = "子类";

    public Child() {
        super();      // 调用父类无参构造(必须是第一行!)
        System.out.println("子类无参构造");
    }

    public Child(String name) {
        super(name);  // 调用父类有参构造(必须是第一行!)
        this.name = name;
        System.out.println("子类有参构造:" + name);
    }

    @Override
    public void show() {
        System.out.println("父类的:" + super.name); // 访问父类的 name
        System.out.println("子类的:" + this.name);   // 访问子类的 name
    }
}

Child c = new Child("小明");
// 输出:
// 父类有参构造:小明
// 子类有参构造:小明

super vs this

  • this:指向当前对象(子类自己的)
  • super:指向父类对象(父类自己的)
  • super():调用父类构造方法,必须写在子类构造方法的第一行
  • this():调用本类的其他构造方法,也必须写在第一行
  • super()this() 不能同时存在(都是第一行)

记忆:this 指向自己,super 指向父亲。构造方法里 super() 是必写的(Java 默认自动加,但有参构造需要手动调)。

5. 继承构造方法特点

java
public class Parent {
    public Parent() {
        System.out.println("父类无参构造");
    }

    public Parent(String name) {
        System.out.println("父类有参构造");
    }
}

public class Child extends Parent {
    public Child() {
        super();  // 自动调用父类无参构造
        System.out.println("子类无参构造");
    }

    public Child(String name) {
        super(name);  // 调用父类有参构造
        System.out.println("子类有参构造");
    }
}

Child c = new Child();
// 输出:
// 父类无参构造
// 子类无参构造

Child c2 = new Child("test");
// 输出:
// 父类有参构造
// 子类有参构造

构造方法执行顺序:先父类,后子类。创建子类对象时,父类构造方法一定会先执行。

6. 父类 private 成员变量访问

java
public class Parent {
    private String name = "父类私有";

    public String getName() {
        return name;  // 通过 public 方法暴露
    }
}

public class Child extends Parent {
    public void print() {
        // System.out.println(name); // ❌ 不能直接访问父类 private 成员
        System.out.println(getName()); // ✅ 通过父类的 public 方法访问
    }
}

子类访问父类 private 成员的方式

  1. 通过父类的 getter 方法(最常用)
  2. 通过父类的 public/protected 方法
  3. 通过 构造方法super(参数) 传值)
java
// 方式3:构造方法
public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }
}

public class Child extends Parent {
    private int age;

    public Child(String name, int age) {
        super(name);  // 把值传给父类构造方法
        this.age = age;
    }
}

private 成员只能在本类访问,子类必须通过方法或构造方法间接访问。这是封装的体现,不是缺陷。