写在前面:这是JavaSE系列的第7篇。继承和多态是面向对象的另外两个核心特性。继承让代码复用成为可能,多态让程序更灵活。今天这篇是OOP的精华,面试必问。


在这里插入图片描述

一、继承:让代码复用成为可能

1.1 为什么需要继承?

不用继承的代码

class Student {
    String name;
    int age;
    void study() { }
}

class Teacher {
    String name;
    int age;  // 重复代码
    void teach() { }  // 不同的方法
}

class Employee {
    String name;
    int age;  // 重复代码
    void work() { }  // 不同的方法
}

使用继承

// 父类:抽出公共部分
class Person {
    String name;
    int age;
    void eat() { }
    void sleep() { }
}

// 子类:继承父类
class Student extends Person {
    void study() { }  // 独有的方法
}

class Teacher extends Person {
    void teach() { }  // 独有的方法
}

1.2 继承的语法

// 用extends表示继承
class 父类 {
    // 公共属性和方法
}

class 子类 extends 父类 {
    // 子类独有的属性和方法
}

示例

// 父类
class Animal {
    String name;
    int age;
    
    public void eat() {
        System.out.println("动物在吃东西");
    }
    
    public void sleep() {
        System.out.println("动物在睡觉");
    }
}

// 子类
class Dog extends Animal {
    // 自动拥有name、age、eat()、sleep()
    
    // 子类独有的方法
    public void bark() {
        System.out.println("狗在叫:汪汪汪");
    }
    
    // 子类重写父类的方法
    @Override
    public void eat() {
        System.out.println("狗在吃狗粮");
    }
}

1.3 继承的特点

// Java只支持单继承
class A { }
class B { }
// class C extends A, B { }  // 错误!不能多继承

// 但可以多层继承
class GrandFather { }
class Father extends GrandFather { }
class Son extends Father { }  // 继承链:A → B → C

1.4 继承后成员的访问

class Father {
    public String name = "父亲";
    private int money = 1000000;  // private子类也访问不了
    
    public void fatherMethod() {
        System.out.println("父亲的方法");
    }
}

class Son extends Father {
    public String name = "儿子";
    
    public void sonMethod() {
        System.out.println("儿子的方法");
    }
    
    public void test() {
        System.out.println(name);           // 儿子(就近原则)
        System.out.println(super.name);      // 父亲(用super访问父类)
        // System.out.println(money);      // 错误!private访问不了
        fatherMethod();                      // 直接调用父类方法
        super.fatherMethod();               // 用super调用父类方法
    }
}

二、方法重写(Override)

2.1 什么是方法重写?

子类对父类的方法不满意,重新定义。

class Phone {
    public void call() {
        System.out.println("打电话");
    }
}

class SmartPhone extends Phone {
    // 重写父类的call方法
    @Override
    public void call() {
        System.out.println("用微信视频通话");
    }
    
    // 新增方法
    public void playGame() {
        System.out.println("玩游戏");
    }
}

2.2 重写的规则

规则 说明
方法名 必须相同
参数列表 必须相同
返回类型 必须相同或是父类返回类型的子类型
访问修饰符 不能比父类更严格
抛出的异常 不能比父类更宽泛

2.3 @Override注解

class Parent {
    public void method() { }
}

class Child extends Parent {
    @Override  // 编译器会检查是否真的是重写
    public void method() {
        System.out.println("重写成功");
    }
    
    @Override  // 编译错误!参数列表不同,是重载不是重写
    public void method(int a) { }
}

2.4 重写vs重载

特性 重写(Override) 重载(Overload)
位置 子类中 同一类中
方法名 必须相同 必须相同
参数列表 必须相同 必须不同
返回类型 必须兼容 可以不同
访问修饰符 不能更严格 可以不同

三、super关键字

3.1 super的作用

super代表父类对象的引用,用于:

  1. 访问父类的成员变量
  2. 访问父类的方法
  3. 调用父类的构造方法

3.2 super访问父类成员

class Father {
    int num = 100;
    
    public void method() {
        System.out.println("父类的方法");
    }
}

class Son extends Father {
    int num = 200;
    
    public void method() {
        System.out.println("子类的方法");
    }
    
    public void test() {
        System.out.println(num);           // 200(就近原则)
        System.out.println(this.num);      // 200
        System.out.println(super.num);     // 100
        
        method();                          // 子类的方法
        this.method();                     // 子类的方法
        super.method();                    // 父类的方法
    }
}

3.3 super调用父类构造方法

class Father {
    String name;
    
    public Father() {
        System.out.println("父类无参构造");
    }
    
    public Father(String name) {
        this.name = name;
        System.out.println("父类有参构造");
    }
}

class Son extends Father {
    int age;
    
    // 子类构造方法中,必须先调用父类构造
    public Son() {
        super();  // 调用父类无参构造(如果不写,编译器会自动添加)
        System.out.println("子类无参构造");
    }
    
    public Son(String name, int age) {
        super(name);  // 调用父类有参构造
        this.age = age;
        System.out.println("子类有参构造");
    }
}

重要规则

  1. 子类构造方法必须先调用父类构造方法
  2. super()必须在构造方法的第一行
  3. this()和super()不能同时出现

四、多态:同一种行为,不同表现

4.1 多态的概念

多态:同一种事物,表现出的不同形态。

// 父类引用指向子类对象
Animal animal = new Dog();  // 编译时类型是Animal,运行时类型是Dog
animal.eat();  // 调用的是Dog的eat方法

4.2 多态的前提

  1. 有继承关系
  2. 子类重写父类方法
  3. 父类引用指向子类对象

4.3 多态的示例

// 父类
class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}

// 子类1
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
    
    public void lookDoor() {
        System.out.println("狗看家");
    }
}

// 子类2
class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("喵喵喵");
    }
}

public class Test {
    public static void main(String[] args) {
        // 多态:父类引用指向子类对象
        Animal a1 = new Dog();  // 向上转型
        Animal a2 = new Cat();  // 向上转型
        
        a1.sound();  // 汪汪汪(调用的是Dog的方法)
        a2.sound();  // 喵喵喵(调用的是Cat的方法)
        
        // a1.lookDoor();  // 编译错误!Animal引用没有lookDoor方法
    }
}

4.4 向上转型和向下转型

// 向上转型(自动)
Animal a = new Dog();  // 小类型转大类型,安全

// 向下转型(强制,可能ClassCastException)
Dog d = (Dog) a;  // 大类型转小类型,不安全
d.lookDoor();  // 可以调用Dog独有的方法

// 向下转型前,先用instanceof判断
Animal a = new Dog();
if (a instanceof Dog) {
    Dog d = (Dog) a;
    d.lookDoor();
}

// 实际应用
public static void doSound(Animal animal) {
    animal.sound();
    // 如果需要调用子类特有方法
    if (animal instanceof Dog) {
        Dog dog = (Dog) animal;
        dog.lookDoor();
    }
}

4.5 多态的应用场景

// 场景1:参数多态
public static void printInfo(Animal animal) {
    animal.sound();
}

// 场景2:返回值多态
public static Animal createAnimal(String type) {
    if ("dog".equals(type)) {
        return new Dog();
    } else if ("cat".equals(type)) {
        return new Cat();
    }
    return new Animal();
}

// 场景3:接口多态
interface Flyable {
    void fly();
}

class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟在飞");
    }
}

class Plane implements Flyable {
    @Override
    public void fly() {
        System.out.println("飞机在飞");
    }
}

五、final关键字

5.1 final修饰变量

// 修饰基本类型:值不能改变
final int NUM = 100;
// NUM = 200;  // 编译错误!

// 修饰引用类型:引用不能改变
final Student s = new Student();
s.setName("张三");  // 可以修改对象属性
// s = new Student();  // 编译错误!不能改变引用

5.2 final修饰方法

class Parent {
    // final方法:不能被子类重写
    public final void method() {
        System.out.println("这是final方法");
    }
}

class Child extends Parent {
    // @Override
    // public void method() { }  // 编译错误!不能重写
}

5.3 final修饰类

// final类:不能被继承
final class String { }  // Java的String就是final类
// class MyString extends String { }  // 编译错误!

5.4 final的应用场景

// 1. 常量
public static final double PI = 3.14159;

// 2. 工具类(不希望被继承)
public final class Math {
    // 私有化构造方法
    private Math() { }
    
    public static int max(int a, int b) {
        return a > b ? a : b;
    }
}

// 3. 模板方法模式
abstract class Game {
    public final void play() {  // 模板方法,final不允许重写
        init();
        start();
        end();
    }
    
    abstract void init();    // 子类实现
    abstract void start();   // 子类实现
    abstract void end();     // 子类实现
}

六、面试高频考点

考点1:this和super的区别

关键字 作用 使用位置
this 访问当前类成员 任何位置
super 访问父类成员 子类中

考点2:构造方法的执行顺序

class GrandFather {
    public GrandFather() {
        System.out.println("祖父构造");
    }
}

class Father extends GrandFather {
    public Father() {
        System.out.println("父亲构造");
    }
}

class Son extends Father {
    public Son() {
        System.out.println("儿子构造");
    }
}

new Son();
// 输出:
// 祖父构造
// 父亲构造
// 儿子构造

考点3:多态的理解

// 编译时类型:声明时的类型
// 运行时类型:实际创建的对象类型

Animal animal = new Dog();
// animal编译时类型是Animal,运行时类型是Dog
// 调用方法时,执行的是Dog的方法(虚方法调用)

考点4:instanceof的使用

// 向下转型前必须用instanceof判断
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.lookDoor();
}

七、总结

今天我们学习了:

  • ✅ 继承的概念和语法
  • ✅ 方法重写(Override)
  • ✅ super关键字
  • ✅ 多态的概念和应用
  • ✅ 向上转型和向下转型
  • ✅ final关键字

重点记忆

  1. Java单继承,extends只能继承一个父类
  2. 多态:父类引用指向子类对象
  3. 重写:子类重新定义父类方法
  4. super访问父类,this访问当前类

下一步预告
Day8我们将学习抽象类和接口——abstract、interface、默认方法、多实现等。


互动话题:你在理解多态的时候,有没有觉得"父类引用指向子类对象"这个概念很绕?欢迎在评论区分享你的理解!

如果这篇文章对你有帮助,欢迎点赞、收藏!这是【JavaSE全面教学】系列的第7篇,关注我看完整套教程 👇


本文为【JavaSE全面教学】系列第7篇,持续更新中…

更多推荐