跳转至

封装 · 继承 · 多态

面向对象三件套。前端人写过 JS class/extends,这里主要理解 Java 的访问控制强类型多态

封装:private + getter/setter

class Account {
    private int balance;          // private:外部不能直接 balance = -50

    public int getBalance() { return balance; }       // getter
    public void deposit(int amount) {                 // setter 里做校验
        if (amount <= 0) return;
        this.balance += amount;
    }
}

封装的价值:把"如何修改 balance"的规则收进类内部,外部只能通过受控的方法访问。JS 没有真正的 private# 私有字段是新特性),Java 的 private 是编译期强制的。

继承:extends + super

class Dog extends Animal { }   // 单继承!一个类只能 extends 一个父类
  • Java 只能单继承(不像 Python 多继承)。要"多继承"的能力用接口(第 09 章)。
  • super 调用父类的构造器/方法,对标 JS 的 super

多态:父类引用指向子类对象

Animal[] zoo = {new Dog(), new Cat()};
for (Animal a : zoo) {
    a.speak();   // Dog 打印"汪汪",Cat 打印"喵喵"——运行时决定
}

这是后端最常用的模式:方法参数声明为父类型,能接收任何子类。Spring 里你会大量看到这种"面向接口/父类编程"。

@Override 是干什么的

class Dog extends Animal {
    @Override               // 告诉编译器"我要重写父类方法"
    public void speak() { }
}

加了 @Override,如果你拼错了方法名(比如写成 speek),编译器立刻报错——它发现父类没有这个方法可重写。不加的话,你以为是重写,其实是新方法,bug 很难查。重写一律加 @Override

instanceof 与强转

Animal a = new Dog();
if (a instanceof Dog) {
    Dog d = (Dog) a;   // 向下转型(强转)后才能调用 Dog 专属方法
    d.bark();
}

完整可运行示例

package com.javaglm.language.ch08;

/**
 * 第 08 章 · 封装、继承、多态。
 * 封装:private 字段 + getter/setter,外部不能乱改。
 * 继承:extends 单继承,super 调父类。
 * 多态:父类引用指向子类对象,调用的是子类重写后的方法。
 */
public class PolyDemo {

    public static void main(String[] args) {
        // === 封装 ===
        Account acc = new Account("Tom");
        acc.deposit(100);
        // acc.balance = -50;   // ✗ 编译报错!balance 是 private,外部不能直接改
        acc.deposit(-30);       // 被 setter 里的校验拦下,余额不变
        System.out.println(acc.getName() + " 余额 = " + acc.getBalance());  // 100

        // === 多态:父类引用指向子类对象 ===
        Animal[] zoo = {new Dog(), new Cat()};
        for (Animal a : zoo) {
            a.speak();   // 运行时根据实际类型,调用各自重写的方法
        }

        // === instanceof:判断真实类型(对标 JS 的 instanceof)===
        Animal a = new Dog();
        if (a instanceof Dog) {
            Dog d = (Dog) a;     // 向下转型(强转)
            d.bark();
        }
    }
}

// ===================== 封装 =====================
class Account {
    private String name;
    private int balance;     // private:外部不可直接访问

    Account(String name) {
        this.name = name;
    }

    // getter:只读访问
    public String getName() { return name; }
    public int getBalance() { return balance; }

    // setter 里做校验,这是"封装"的核心价值
    public void deposit(int amount) {
        if (amount <= 0) {
            System.out.println("金额必须为正,忽略:" + amount);
            return;
        }
        this.balance += amount;
    }
}

// ===================== 继承 + 多态 =====================
class Animal {
    public void speak() {
        System.out.println("...");
    }
}

class Dog extends Animal {        // extends 单继承
    @Override                     // 重写标记(编译器帮你检查签名是否真的覆盖了父类方法)
    public void speak() {
        System.out.println("汪汪!");
    }

    public void bark() {
        System.out.println("Dog 专属方法");
    }
}

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

前端人对照

JS Java 备注
class Dog extends Animal Java 单继承
super.speak() 调父类
无真正私有(# 除外) private 编译强制 封装更强
obj instanceof Cls 判断类型
无重写标记 @Override 防拼错,必加

:octicons-arrow-left-16: 上一章:面向对象基础 | 下一章:接口与抽象类