封装、继承、多态

封装、继承、多态

一、封装

把数据和行为包在一起,隐藏内部细节,只暴露必要接口。

1、封装的作用:

保护数据,防止被随意修改

外部只需知道"怎么用",不用管"怎么实现"

改内部实现不影响外部调用。

2、怎么实现

属性私有化:用 private 修饰

java 复制代码
class Student {
    // 属性私有化
    private String name;
    private int age;

    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

提供公共方法:getter / setter 或业务方法

java 复制代码
 // getter方法
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // setter方法(含校验)
    public void setName(String name) {
        this.name = name;
    }

在方法里做校验:保证数据合法

java 复制代码
 public void setAge(int age) {
        if (age > 0 && age < 150) {
            this.age = age;
        } else {
            System.out.println("年龄不合法!");
        }
    }    

二、继承

子类自动拥有父类的属性和方法,实现代码复用

1、作用

复用:父类写好的东西,子类直接用

扩展:子类可以加自己的新功能

重写:子类可以改父类的行为

2、如何使用

① 创建父类
java 复制代码
public class Animal {
    protected String name;
    protected int age;

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

    // 父类的通用方法 ------ 子类会【重写】来修改行为
    public String speak() {
        return name + " 发出了声音";
    }

    // 父类的通用方法 ------ 子类直接【继承使用】
    public String info() {
        return name + "," + age + " 岁";
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + ": " + info();
    }
}
② 创建子类 ------ 使用 extends 继承父类
java 复制代码
// Dog 继承 Animal,自动拥有 name、age 属性和 info() 方法
public class Dog extends Animal {
    // 子类独有的属性
    private String breed;   // 品种

    // 子类构造器:用 super 调用父类构造器
    public Dog(String name, int age, String breed) {
        super(name, age);      // 先让父类初始化自己的部分
        this.breed = breed;    // 再初始化子类独有的部分
    }

    // ======== 修改父类行为:重写 speak() ========
    @Override
    public String speak() {
        return name + " 汪汪汪!";   // 不再是"发出了声音",而是具体的狗叫
    }

    // ======== 子类增加新功能:子类独有的方法 ========
    public String fetch() {
        return name + " 去捡球啦!";
    }

    // 子类也可以扩展 toString(),在父类基础上追加品种信息
    @Override
    public String toString() {
        return super.toString() + ",品种:" + breed;
    }
}

再写一个子类 Cat,展示不同的重写效果:

java 复制代码
public class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }

    // Cat 对 speak() 做不同的重写
    @Override
    public String speak() {
        return name + " 喵喵喵~";
    }

    // Cat 独有的新方法
    public String climb() {
        return name + " 爬上了屋顶!";
    }
}
③ 调用 ------ 创建子类实例,体验继承、重写、扩展
java 复制代码
public class Test {
    public static void main(String[] args) {
        // --- 1. 创建子类实例 ---
        Dog dog = new Dog("旺财", 3, "柴犬");
        Cat cat = new Cat("咪咪", 2);

        // --- 2. 直接使用父类继承过来的方法 ---
        System.out.println(dog.info());   // 输出:旺财,3 岁
        System.out.println(cat.info());   // 输出:咪咪,2 岁

        // --- 3. 调用被重写的方法 ------ 子类行为覆盖父类 ---
        System.out.println(dog.speak());  // 输出:旺财 汪汪汪!
        System.out.println(cat.speak());  // 输出:咪咪 喵喵喵~
        // 如果没有重写 speak(),就会执行父类的 "旺财 发出了声音"

        // --- 4. 调用子类独有的新方法 ---
        System.out.println(dog.fetch());  // 输出:旺财 去捡球啦!
        System.out.println(cat.climb());  // 输出:咪咪 爬上了屋顶!

        // --- 5. 多态:父类引用指向子类对象 ---
        Animal a1 = new Dog("小黑", 5, "拉布拉多");
        Animal a2 = new Cat("花花", 1);
        System.out.println(a1.speak());   // 输出:小黑 汪汪汪!(运行时实际是 Dog)
        System.out.println(a2.speak());   // 输出:花花 喵喵喵~(运行时实际是 Cat)
    }
}

3、要点小结

场景 怎么做 关键代码
继承父类 类声明加 extends 父类名 class Dog extends Animal
调用父类构造器 构造器第一行写 super(...) super(name, age)
修改父类行为(重写) 方法上加 @Override,方法签名不变 public String speak() { ... }
增加子类功能 直接写新属性 / 新方法 private String breed; / public String fetch()
调用父类被重写的方法 在子类中用 super.方法名() super.toString()

三、多态

同一个方法调用,根据对象的实际类型,执行不同的行为。简单说:一个接口,多种实现。

1、作用

统一调用,代码简洁

加新类型时,不用改调用方代码

调用方只依赖父类(抽象),不依赖具体子类

2、如何使用

前提:沿用上面继承章节写好的 Animal(父类)、Dog 和 Cat(子类),且子类都重写了 speak()。

① 核心写法:父类引用指向子类对象(向上转型,自动完成)
java 复制代码
public class TestPolymorphism {
    public static void main(String[] args) {
        Animal a1 = new Dog("旺财", 3, "柴犬");  // 左边是父类,右边是子类
        Animal a2 = new Cat("咪咪", 2);

        // 同一个调用 a.speak(),执行哪个版本由"对象的真实类型"决定
        System.out.println(a1.speak());   // 输出:旺财 汪汪汪!------ 真实对象是 Dog
        System.out.println(a2.speak());   // 输出:咪咪 喵喵喵~ ------ 真实对象是 Cat
    }
}

口诀:编译看左边,运行看右边。

  • 编译时:a1 的类型是 Animal,所以 Animal 里必须有 speak(),否则编译报错;
  • 运行时:JVM 看真实对象是 Dog 还是 Cat,自动执行对应子类重写的版本(动态绑定)。
② 多态的好处:统一处理一批不同子类
java 复制代码
Animal[] animals = {
    new Dog("小黑", 5, "拉布拉多"),
    new Cat("花花", 1),
    new Dog("大黄", 4, "土狗")
};

// 不用 if/else 判断类型,同一句代码处理所有动物
for (Animal a : animals) {
    System.out.println(a.speak());
}
③ 方法参数用父类,调用方可以传任意子类
java 复制代码
// 调用方只依赖父类 Animal,不依赖任何具体子类
public static void makeSpeak(Animal a) {
    System.out.println(a.speak());
}

// 传 Dog、Cat 都可以
makeSpeak(new Dog("豆豆", 2, "泰迪"));   // 输出:豆豆 汪汪汪!
makeSpeak(new Cat("雪球", 1));          // 输出:雪球 喵喵喵~
④ 加新子类,调用方代码一行都不用改
java 复制代码
// 以后新增一个 Pig 子类,上面的循环和 makeSpeak() 原封不动就能用
public class Pig extends Animal {
    public Pig(String name, int age) {
        super(name, age);
    }

    @Override
    public String speak() {
        return name + " 哼哼哼~";
    }
}

makeSpeak(new Pig("佩奇", 3));   // 输出:佩奇 哼哼哼~

这就是「开闭原则」:对扩展开放(加新子类),对修改封闭(不用改老代码)。

⑤ 注意:父类引用不能直接调用子类独有方法
java 复制代码
Animal a1 = new Dog("旺财", 3, "柴犬");
// a1.fetch();          // 编译报错!Animal 类型里没有 fetch()

// 必须先 instanceof 判断真实类型,再向下转型(强制转换)
if (a1 instanceof Dog) {
    Dog d = (Dog) a1;              // 向下转型
    System.out.println(d.fetch()); // 输出:旺财 去捡球啦!
}

向下转型有风险:真实对象不是该类型时会抛 ClassCastException,所以转型前一定要用 instanceof 判断。

3、小结

多态的三大前提

要素 作用
继承 提供类型关系
重写 提供差异化实现
父类引用 提供统一的调用入口
三者齐备 才构成多态

封装、继承、多态的关系

关系 说明
封装 → 继承 封装让父类的内部实现对外不可见,子类只能通过受保护的接口来扩展,保证了继承的安全性
继承 → 多态 没有继承(或接口实现),就没有"父类引用指向子类对象"这种统一类型的基础
封装 → 多态 封装保证了方法签名的稳定性,多态调用时才能依赖统一的接口契约
多态 ← 继承 + 重写 多态是继承和方法重写共同作用的结果
相关推荐
Ysx1 小时前
比"本地全绿"更可怕的坑:"交付了"不等于"生效了"
java·后端
2301_786756601 小时前
2026 JCR 秋季数据重载解读:影响因子为什么会变?附期刊影响力数据批量追踪方案
java·服务器·前端
用户7771298509121 小时前
代码的命名规范有哪些?
java
旋律4141 小时前
为什么需要命名规范?有哪些命名规范?
java
2301_786756601 小时前
中科院分区表停发后,期刊评价的技术逻辑:从期刊超越指数到多指标选刊方案
java·数据库·windows
Wx-bishekaifayuan2 小时前
springboot铜仁非遗之家76938-计算机课程设计、毕业设计
java·spring boot·后端·spring·django·课程设计·旅游
顽疲2 小时前
java vue springboot 养老系统源码详解:退住 care_out 审批结算与腾床事务实践
java·vue.js·spring boot·vue养老·springboot养老·java养老
geats人山人海2 小时前
java 7异常
android·java·开发语言
斯内普吖2 小时前
(开源)线上花店系统实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源