【Java 基础编程】封装、继承、多态一篇讲透:Java 面向对象三大特性详解 + 实战

面向对象中级特性(封装、继承、多态)是 Java 面向对象编程的核心,掌握这些特性能够编写更加灵活、可维护的代码,是 Java 开发的基础。

⚡ 快速参考

  • 包(Package):用于组织和管理类,避免类名冲突,命名规范:com.公司名.项目名.模块名
  • 访问修饰符:publicprotected默认private,控制访问范围
  • 封装:隐藏实现细节,通过 getter/setter 方法访问属性
  • 继承:使用 extends 关键字,子类继承父类的属性和方法
  • 多态:同一方法在不同对象上表现出不同行为,提高代码灵活性

📚 学习目标

  1. 理解包的概念和作用,掌握包的命名规范和使用
  2. 掌握四种访问修饰符的使用场景
  3. 理解封装的概念,掌握 getter/setter 方法
  4. 理解继承的概念和特点,掌握 super 关键字
  5. 理解多态的概念和实现方式,掌握向上转型和向下转型

一、面向对象中级概述

1.1 什么是面向对象中级特性?

面向对象中级特性: 包括封装、继承、多态三大特性,是面向对象编程的核心思想。

核心概念:

  • 封装:隐藏对象的内部实现细节,只暴露必要的接口
  • 继承:子类继承父类的属性和方法,实现代码复用
  • 多态:同一接口可以有不同的实现方式,提高代码灵活性

二、包(Package)

2.1 包的概念

包的本质: 实际上就是创建不同的文件夹来保存类文件,用于组织和管理类。

作用:

  • 避免类名冲突
  • 便于管理和查找类
  • 控制访问权限

2.2 包的命名规范

规则:

  • 只能包含数字、字母、下划线、小圆点
  • 不能用数字开头
  • 不能是关键字或保留字
  • 一般是小写字母 + 小圆点

命名约定:

复制代码
公司域名倒置.项目名.模块名

例如:
com.alibaba.fastjson
com.baidu.aip.speech
org.springframework.boot

2.3 常用的包

包名 说明 是否需要导入
java.lang.* 基本包(String、System、Math等) 自动导入
java.util.* 工具包(Scanner、List、Map等) 需要导入
java.io.* IO流包(File、InputStream等) 需要导入
java.net.* 网络包(Socket、URL等) 需要导入
java.awt.* GUI界面包 需要导入

2.4 包的使用

导入包的语法
java 复制代码
import 包名.类名;        // 导入单个类
import 包名.*;          // 导入包下所有类(不推荐)

示例:

java 复制代码
// 方式一:导入具体类(推荐)
import java.util.Scanner;
import java.util.ArrayList;

// 方式二:导入整个包
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<String> list = new ArrayList<>();
    }
}

1.5 注意事项

包的声明和导入顺序:

java 复制代码
package com.example.demo;  // 1. 包声明(必须在第一行)

import java.util.Scanner;  // 2. 导入语句
import java.util.List;

public class Demo {        // 3. 类定义
    // ...
}

重点:

  • package 声明必须是第一句代码(注释除外)
  • 一个类中最多只有一句 package
  • import 可以有多句,没有顺序要求
  • import 必须在 package 之后,类定义之前

三、访问修饰符

2.1 四种访问修饰符

Java 提供了 4 种访问修饰符,用于控制类、方法、属性的访问权限。

修饰符 本类 同包 子类 不同包 说明
public 公开级别,对外公开
protected 受保护级别,对子类和同包公开
默认(无修饰符) 默认级别,只对同包公开
private 私有级别,只对本类公开

2.2 使用示例

java 复制代码
package com.example;

public class Person {
    public String name;        // 任何地方都可以访问
    protected int age;         // 子类和同包可以访问
    String address;            // 同包可以访问(默认)
    private String password;   // 只有本类可以访问
    
    public void publicMethod() {
        // 公开方法
    }
    
    protected void protectedMethod() {
        // 受保护方法
    }
    
    void defaultMethod() {
        // 默认方法
    }
    
    private void privateMethod() {
        // 私有方法
    }
}

2.3 使用建议

最佳实践:

  1. :通常使用 public 或 默认修饰符
  2. 属性 :通常使用 private,通过 getter/setter 访问
  3. 方法:根据需要选择合适的修饰符
  4. 构造器 :通常使用 public,单例模式使用 private

四、封装(Encapsulation)

3.1 封装的概念

定义: 将数据(属性)和操作数据的方法绑定在一起,隐藏内部实现细节,只对外提供公共接口。

核心思想: "高内聚,低耦合"

3.2 封装的好处

  1. 隐藏实现细节:外部只需知道怎么用,不需要知道怎么实现
  2. 数据验证:可以对数据进行合法性检查
  3. 保证数据安全:防止数据被随意修改
  4. 易于维护:修改内部实现不影响外部使用

3.3 封装的实现步骤

三步实现封装:

① 属性私有化
java 复制代码
public class Person {
    private String name;
    private int age;
    private double salary;
}
② 提供 public 的 setter 方法
java 复制代码
public void setAge(int age) {
    // 数据验证
    if (age < 0 || age > 150) {
        System.out.println("年龄不合法!");
        return;
    }
    this.age = age;
}

public void setSalary(double salary) {
    if (salary < 0) {
        System.out.println("薪水不能为负!");
        return;
    }
    this.salary = salary;
}
③ 提供 public 的 getter 方法
java 复制代码
public int getAge() {
    return age;
}

public double getSalary() {
    // 可以在返回前做一些处理
    return salary;
}

3.4 完整示例

java 复制代码
public class Person {
    // 1. 属性私有化
    private String name;
    private int age;
    private double salary;
    
    // 2. 构造器
    public Person(String name, int age, double salary) {
        setName(name);   // 使用 setter,确保数据验证
        setAge(age);
        setSalary(salary);
    }
    
    // 3. setter 方法(带数据验证)
    public void setName(String name) {
        if (name == null || name.length() < 2 || name.length() > 20) {
            System.out.println("姓名长度应在2-20之间");
            return;
        }
        this.name = name;
    }
    
    public void setAge(int age) {
        if (age < 0 || age > 150) {
            System.out.println("年龄应在0-150之间");
            return;
        }
        this.age = age;
    }
    
    public void setSalary(double salary) {
        if (salary < 0) {
            System.out.println("薪水不能为负");
            return;
        }
        this.salary = salary;
    }
    
    // 4. getter 方法
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    public double getSalary() {
        return salary;
    }
    
    // 5. 信息展示
    public String info() {
        return "姓名:" + name + ",年龄:" + age + ",薪水:" + salary;
    }
}

五、继承(Inheritance)

4.1 继承的概念

定义: 子类继承父类的属性和方法,实现代码复用。

语法:

java 复制代码
class 子类 extends 父类 {
    // 子类特有的属性和方法
}

4.2 继承的特点

Java 继承的特点:

  1. 单继承:一个子类只能有一个直接父类
  2. 传递性:A 继承 B,B 继承 C,则 A 也拥有 C 的属性和方法
  3. 所有类的父类 :所有类都直接或间接继承自 Object
  4. 私有属性不能继承 :子类不能继承父类的 private 成员
  5. 构造器不能继承 :但子类可以通过 super() 调用父类构造器

4.3 继承的基本使用

示例:

java 复制代码
// 父类
class Animal {
    private String name;
    private int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void eat() {
        System.out.println(name + "在吃东西");
    }
    
    public void sleep() {
        System.out.println(name + "在睡觉");
    }
}

// 子类 - 狗
class Dog extends Animal {
    private String breed;  // 品种
    
    public Dog(String name, int age, String breed) {
        super(name, age);  // 调用父类构造器
        this.breed = breed;
    }
    
    // 子类特有方法
    public void bark() {
        System.out.println("汪汪汪!");
    }
    
    // 重写父类方法
    @Override
    public void eat() {
        System.out.println("狗狗在吃狗粮");
    }
}

// 子类 - 猫
class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }
    
    public void catchMouse() {
        System.out.println("猫在抓老鼠");
    }
    
    @Override
    public void eat() {
        System.out.println("猫在吃鱼");
    }
}

4.4 super 关键字

super 的三种用法:

① 访问父类属性
java 复制代码
class Parent {
    protected String name = "父类";
}

class Child extends Parent {
    private String name = "子类";
    
    public void showName() {
        System.out.println(name);        // 子类
        System.out.println(this.name);   // 子类
        System.out.println(super.name);  // 父类
    }
}
② 调用父类方法
java 复制代码
class Parent {
    public void show() {
        System.out.println("父类方法");
    }
}

class Child extends Parent {
    @Override
    public void show() {
        super.show();  // 调用父类方法
        System.out.println("子类方法");
    }
}
③ 调用父类构造器
java 复制代码
class Parent {
    private String name;
    
    public Parent(String name) {
        this.name = name;
    }
}

class Child extends Parent {
    private int age;
    
    public Child(String name, int age) {
        super(name);  // 调用父类构造器(必须是第一句)
        this.age = age;
    }
}

注意事项:

  • super() 必须是构造器的第一句
  • 如果没有显式调用 super(),编译器会自动添加 super()
  • super()this() 不能同时出现在构造器中

4.5 方法重写(Override)

重写的规则:

项目 要求
方法名 必须相同
参数列表 必须相同
返回类型 相同或子类
访问修饰符 不能更严格(只能相同或更宽松)
异常 不能抛出新的或更广的异常
注解 建议使用 @Override

示例:

java 复制代码
class Animal {
    public Object getInfo() {  // 返回 Object
        return "动物";
    }
    
    protected void show() {    // protected
        System.out.println("Animal show");
    }
}

class Dog extends Animal {
    @Override
    public String getInfo() {  // 返回 String(Object的子类) ✅
        return "狗";
    }
    
    @Override
    public void show() {       // public(比 protected 更宽松) ✅
        System.out.println("Dog show");
    }
    
    // 以下写法是错误的:
    // @Override
    // private void show() { }  // ❌ private 比 protected 更严格
}

六、多态(Polymorphism)

5.1 多态的概念

定义: 同一个方法调用,由于对象不同可能会有不同的行为。

多态的前提:

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

5.2 多态的体现

编译时类型 vs 运行时类型:

java 复制代码
Animal animal = new Dog();
//  ↑           ↑
// 编译时类型   运行时类型

示例:

java 复制代码
class Animal {
    public void eat() {
        System.out.println("动物在吃东西");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }
    
    public void bark() {
        System.out.println("汪汪汪");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫在吃鱼");
    }
}

// 使用多态
public class Test {
    public static void main(String[] args) {
        // 多态数组
        Animal[] animals = new Animal[3];
        animals[0] = new Dog();
        animals[1] = new Cat();
        animals[2] = new Animal();
        
        // 多态调用
        for (Animal animal : animals) {
            animal.eat();  // 运行时决定调用哪个方法
        }
        // 输出:
        // 狗在吃骨头
        // 猫在吃鱼
        // 动物在吃东西
    }
}

5.3 多态的特点

向上转型(自动)
java 复制代码
Animal animal = new Dog();  // 自动向上转型
animal.eat();               // 可以调用 Dog 重写的 eat()
// animal.bark();           // ❌ 不能调用 Dog 特有的方法
向下转型(强制)
java 复制代码
Animal animal = new Dog();
Dog dog = (Dog) animal;     // 向下转型
dog.bark();                 // ✅ 可以调用 Dog 特有的方法

// 注意:转型前要先判断类型
if (animal instanceof Dog) {
    Dog d = (Dog) animal;
    d.bark();
}

5.4 instanceof 运算符

作用: 判断对象是否是某个类的实例。

语法:

java 复制代码
对象 instanceof 类名

示例:

java 复制代码
Animal animal = new Dog();

System.out.println(animal instanceof Dog);     // true
System.out.println(animal instanceof Animal);  // true
System.out.println(animal instanceof Object);  // true
System.out.println(animal instanceof Cat);     // false

// 安全的向下转型
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

5.5 多态的好处

1. 降低耦合性

java 复制代码
// 不使用多态(耦合度高)
public void feedDog(Dog dog) {
    dog.eat();
}
public void feedCat(Cat cat) {
    cat.eat();
}

// 使用多态(耦合度低)
public void feedAnimal(Animal animal) {
    animal.eat();  // 可以传入任何 Animal 的子类
}

2. 易于扩展

java 复制代码
// 新增一个 Bird 类,无需修改 feedAnimal 方法
class Bird extends Animal {
    @Override
    public void eat() {
        System.out.println("鸟在吃虫子");
    }
}

feedAnimal(new Bird());  // 直接使用

3. 提高代码复用性


七、面试常见问题

⭐⭐⭐⭐⭐ Q1: 封装、继承、多态分别是什么?

答案:

封装:

  • 将数据和操作数据的方法绑定在一起,隐藏内部实现细节
  • 实现方式:属性私有化 + 提供 getter/setter 方法
  • 好处:隐藏细节、数据验证、易于维护

继承:

  • 子类继承父类的属性和方法,实现代码复用
  • 特点:单继承、传递性、所有类继承自 Object
  • 关键字:extendssuper

多态:

  • 同一个方法调用,对象不同行为不同
  • 前提:继承关系、方法重写、父类引用指向子类对象
  • 好处:降低耦合、易于扩展、提高复用性

⭐⭐⭐⭐⭐ Q2: 重载和重写的区别?

答案:

详见面向对象初级章节或面试题汇总。


⭐⭐⭐⭐ Q3: super 和 this 的区别?

答案:

特性 this super
含义 当前对象的引用 父类对象的引用
访问属性 this.属性 访问本类属性 super.属性 访问父类属性
调用方法 this.方法() 调用本类方法 super.方法() 调用父类方法
调用构造器 this() 调用本类构造器 super() 调用父类构造器
位置要求 必须是构造器第一句 必须是构造器第一句
能否共存 不能同时出现在构造器中 不能同时出现在构造器中

⭐⭐⭐⭐⭐ Q4: 多态的向上转型和向下转型是什么?

答案:

向上转型(自动):

  • 子类对象赋值给父类引用
  • 语法:父类 引用 = new 子类();
  • 特点:自动完成,安全
  • 限制:只能调用父类中定义的方法

向下转型(强制):

  • 父类引用转换为子类引用
  • 语法:子类 引用 = (子类) 父类引用;
  • 特点:需要强制转换,可能失败
  • 用途:调用子类特有的方法

示例:

java 复制代码
// 向上转型
Animal animal = new Dog();  // 自动

// 向下转型
Dog dog = (Dog) animal;     // 强制
dog.bark();

// 错误的向下转型
Animal animal2 = new Cat();
Dog dog2 = (Dog) animal2;   // ❌ ClassCastException

⭐⭐⭐⭐ Q5: 什么时候使用 protected 修饰符?

答案:

使用场景:

  1. 需要被子类访问的属性或方法
  2. 同包内的类需要访问
  3. 不希望对外完全公开(不用 public)

示例:

java 复制代码
class Parent {
    protected void init() {
        // 初始化方法,子类可以重写
    }
}

class Child extends Parent {
    @Override
    protected void init() {
        super.init();
        // 子类自己的初始化
    }
}

📚 本章总结

  1. 包(Package) 用于组织和管理类,避免命名冲突
  2. 访问修饰符 控制类、方法、属性的访问权限(public > protected > 默认 > private)
  3. 封装 是面向对象的核心特性,通过私有化属性 + 公开方法实现
  4. 继承 实现代码复用,Java 只支持单继承
  5. 多态 是面向对象的精髓,降低耦合、提高扩展性

重点掌握:

  • ✅ 四种访问修饰符的使用场景
  • ✅ 封装的实现步骤(private + getter/setter)
  • ✅ 继承的特点和 super 关键字
  • ✅ 多态的前提条件和使用方法
  • ✅ 向上转型和向下转型
相关推荐
寻寻觅觅☆6 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
YJlio6 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
l1t7 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
青云计划7 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿7 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar1238 小时前
C++使用format
开发语言·c++·算法
山塘小鱼儿8 小时前
本地Ollama+Agent+LangGraph+LangSmith运行
python·langchain·ollama·langgraph·langsimth
探路者继续奋斗8 小时前
IDD意图驱动开发之意图规格说明书
java·规格说明书·开发规范·意图驱动开发·idd
码说AI8 小时前
python快速绘制走势图对比曲线
开发语言·python