前置知识: Java

面向对象编程

6 minIntermediate2026/5/3

类与对象、封装、继承、多态与抽象类。

1. 与对象 (Class & Object)

1.1 的定义

是对象的模板,定义了对象的属性和行为。

 public class Student {
  // 属性 (成员变量)
  private String name;
  private int age;
  private String major;
  // 行为 (方法)
  public void study() {
  System.out.println(name + " is studying.");
  }
  public void introduce() {
  System.out.println("I'm " + name + ", " + age + " years old, major in " + major);
  }
 }

1.2 的结构

  • 成员变量 (Fields): 的属性,存储对象的状态
  • 方法 (Methods): 的行为,定义对象的操作
  • 构造器 (Constructors): 用于创建对象的特殊方法
  • 代码块 (Blocks): 静态代码块和实例代码块
  • 内部类 (Inner Classes): 中定义的

1.3 对象的创建与使用

1.3.1 对象的创建

使用 new 关键字创建对象。

 // 创建对象
 Student student = new Student();
 // 访问对象的属性和方法
 student.setName("Alice");
 student.setAge(20);
 student.setMajor("Computer Science");
 student.study();
 student.introduce();

1.3.2 对象的内存布局

  • 栈 (Stack): 存放对象引用变量
  • 堆 (Heap): 存放对象的实际数据
 栈 堆

 │ student │─────→│ name: null │
 └──────────┘ │ age: 0 │
  │ major: null│
  └────────────┘

1.4 构造器 (Constructors)

构造器用于初始化对象,与同名,无返回值。

1.4.1 默认构造器

如果中没有定义构造器,编译器会自动生成一个无参构造器。

 public class Student {
  // 默认构造器(由编译器生成)
  public Student() {
  }
 }

1.4.2 自定义构造器

可以定义多个构造器,实现方法重载。

 public class Student {
  private String name;
  private int age;
  private String major;
  // 无参构造器
  public Student() {
  }
  // 带参数的构造器
  public Student(String name, int age) {
  this.name = name;
  this.age = age;
  }
  // 全参构造器
  public Student(String name, int age, String major) {
  this.name = name;
  this.age = age;
  this.major = major;
  }
 }

1.4.3 构造器的调用

 // 使用无参构造器
 Student student1 = new Student();
 // 使用带参数的构造器
 Student student2 = new Student("Bob", 21);
 // 使用全参构造器
 Student student3 = new Student("Charlie", 22, "Software Engineering");

2. 封装 (Encapsulation)

2.1 封装的概念

封装是指将对象的状态和行为封装起来,只暴露必要的接口,隐藏实现细节。

2.2 访问修饰符

修饰符同包任意位置
private
default
protected
public

2.3 封装的实现

使用 private 修饰符隐藏属性,通过 getter/setter 方法暴露接口

 public class Student {
  // 私有属性
  private String name;
  private int age;
  private String major;
  // Getter 方法
  public String getName() {
  return name;
  }
  public int getAge() {
  return age;
  }
  public String getMajor() {
  return major;
  }
  // Setter 方法
  public void setName(String name) {
  this.name = name;
  }
  public void setAge(int age) {
  if (age >= 0 && age <= 150) {
  this.age = age;
  } else {
  System.out.println("Invalid age");
  }
  }
  public void setMajor(String major) {
  this.major = major;
  }
 }

2.4 封装的优点

  • 安全性: 防止外部直接修改对象状态
  • 可维护性: 内部实现可以自由修改,不影响外部使用
  • 可读性: 明确对象的接口和职责
  • 灵活性: 可以在 setter 中添加验证逻辑

3. 继承 (Inheritance)

3.1 继承的概念

继承是指一个(子)继承另一个(父)的属性和方法,实现代码复用。

3.2 继承的语法

使用 extends 关键字。

 // 父类
 public class Animal {
  protected String name;
  public void eat() {
  System.out.println(name + " is eating.");
  }
  public void sleep() {
  System.out.println(name + " is sleeping.");
  }
 }
 // 子类
 public class Dog extends Animal {
  public void bark() {
  System.out.println(name + " is barking.");
  }
 }

3.3 继承的特性

  • 单继承: Java 只支持单继承,一个只能有一个直接父
  • 传递性: 如果 A 继承 B,B 继承 C,则 A 间接继承 C
  • 方法重写: 子可以重写父的方法
  • super 关键字: 用于访问父的成员和构造器

3.4 super 关键字的使用

3.4.1 访问父的成员变量

 public class Dog extends Animal {
  private String breed;
  public Dog(String name, String breed) {
  super.name = name; // 访问父类的成员变量
  this.breed = breed;
  }
 }

3.4.2 调用父的方法

 public class Dog extends Animal {
  @Override
  public void eat() {
  super.eat(); // 调用父类的 eat 方法
  System.out.println("Dog eats bones.");
  }
 }

3.4.3 调用父的构造器

 public class Animal {
  protected String name;
  public Animal(String name) {
  this.name = name;
  }
 }
 public class Dog extends Animal {
  private String breed;
  public Dog(String name, String breed) {
  super(name); // 调用父类的构造器
  this.breed = breed;
  }
 }

3.5 方法重写 (Override)

3.5.1 方法重写的规则

  • 方法名相同
  • 参数列表相同
  • 返回类型相同或为子类类型 (协变返回型)
  • 访问修饰符不能更严格
  • 不能抛出比父类方法更多的异常

3.5.2 方法重写的示例

 public class Animal {
  public void makeSound() {
  System.out.println("Animal makes sound.");
  }
 }
 public class Cat extends Animal {
  @Override
  public void makeSound() {
  System.out.println("Cat meows.");
  }
 }
 public class Dog extends Animal {
  @Override
  public void makeSound() {
  System.out.println("Dog barks.");
  }
 }

4. 多态 (Polymorphism)

4.1 多态的概念

多态是指同一行为在不同对象上有不同的表现形式。

4.2 多态的必要条件

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

4.3 多态的示例

 // 父类引用指向子类对象
 Animal animal1 = new Cat();
 animal1.makeSound(); // 输出: Cat meows.
 Animal animal2 = new Dog();
 animal2.makeSound(); // 输出: Dog barks.

4.4 多态的原理

  • 编译时类型: 变量声明的型(父型)
  • 运行时类型: 变量实际指向的对象型(子型)
  • 方法调用: 编译时检查父是否有该方法,运行时执行子重写的方法

4.5 多态的优点

  • 可扩展性: 新增子不影响现有代码
  • 代码复用: 统一使用父引用处理不同子对象
  • 灵活性: 运行时动态绑定方法实现

5. this 关键字

5.1 this 关键字的作用

  • 指向当前对象
  • 区分成员变量和局部变量
  • 调用本类的其他构造器
  • 返回当前对象

5.2 this 关键字的使用

5.2.1 区分成员变量和局部变量

 public class Student {
  private String name;
  public void setName(String name) {
  this.name = name; // this.name 指成员变量,name 指局部变量
  }
 }

5.2.2 调用本的其他构造器

 public class Student {
  private String name;
  private int age;
  public Student() {
  this("Unknown", 0); // 调用带两个参数的构造器
  }
  public Student(String name) {
  this(name, 0); // 调用带两个参数的构造器
  }
  public Student(String name, int age) {
  this.name = name;
  this.age = age;
  }
 }

5.2.3 返回当前对象

 public class Student {
  private String name;
  private int age;
  public Student setName(String name) {
  this.name = name;
  return this; // 返回当前对象,支持链式调用
  }
  public Student setAge(int age) {
  this.age = age;
  return this; // 返回当前对象,支持链式调用
  }
 }
 // 链式调用
 Student student = new Student().setName("Alice").setAge(20);

6. 面向对象的设计原则

6.1 单一职责原则 (SRP)

一个应该只负责一项职责。

6.2 开放-封闭原则 (OCP)

软件实体应该对扩展开放,对修改封闭。

6.3 里氏替换原则 (LSP)

应该能够替换父而不影响程序的正确性。

6.4 依赖倒置原则 (DIP)

高层模块不应该依赖低层模块,两者都应该依赖抽象。

6.5 接口隔离原则 (ISP)

客户端不应该依赖它不需要的接口

7. 实际应用案例

7.1 简单的学生管理系统

 // 基类
 public class Person {
  private String name;
  private int age;
  // 构造器、getter/setter 方法
 }
 // 子类
 public class Student extends Person {
  private String studentId;
  private String major;
  // 构造器、getter/setter 方法
  public void study() {
  System.out.println(getName() + " is studying " + major);
  }
 }
 // 子类
 public class Teacher extends Person {
  private String teacherId;
  private String subject;
  // 构造器、getter/setter 方法
  public void teach() {
  System.out.println(getName() + " is teaching " + subject);
  }
 }
 // 测试
 public class Test {
  public static void main(String[] args) {
  Student student = new Student();
  student.setName("Alice");
  student.setAge(20);
  student.setStudentId("S12345");
  student.setMajor("Computer Science");
  student.study();
  Teacher teacher = new Teacher();
  teacher.setName("Mr. Smith");
  teacher.setAge(35);
  teacher.setTeacherId("T67890");
  teacher.setSubject("Java Programming");
  teacher.teach();
  }
 }

7.2 形状的多态示例

 // 抽象基类
 public abstract class Shape {
  public abstract double calculateArea();
  public abstract double calculatePerimeter();
 }
 // 子类
 public class Circle extends Shape {
  private double radius;
  public Circle(double radius) {
  this.radius = radius;
  }
  @Override
  public double calculateArea() {
  return Math.PI * radius * radius;
  }
  @Override
  public double calculatePerimeter() {
  return 2 * Math.PI * radius;
  }
 }
 // 子类
 public class Rectangle extends Shape {
  private double width;
  private double height;
  public Rectangle(double width, double height) {
  this.width = width;
  this.height = height;
  }
  @Override
  public double calculateArea() {
  return width * height;
  }
  @Override
  public double calculatePerimeter() {
  return 2 * (width + height);
  }
 }
 // 测试
 public class Test {
  public static void main(String[] args) {
  Shape[] shapes = new Shape[2];
  shapes[0] = new Circle(5);
  shapes[1] = new Rectangle(4, 6);
  for (Shape shape : shapes) {
  System.out.println("Area: " + shape.calculateArea());
  System.out.println("Perimeter: " + shape.calculatePerimeter());
  System.out.println();
  }
  }
 }

8. 常见陷阱

8.1 构造器调用顺序

  • 构造器总是在子构造器之前执行
  • 如果子构造器没有显式调用父构造器,会自动调用父的无参构造器
  • 如果父没有无参构造器,子必须显式调用父的有参构造器

8.2 方法重写与方法重载的区别

  • 方法重写:发生在父子之间,方法名、参数列表相同
  • 方法重载:发生在同一中,方法名相同,参数列表不同

8.3 多态的局限性

  • 多态只适用于方法,不适用于属性
  • 引用不能直接调用子特有的方法,需要强制型转换

8.4 继承的滥用

  • 不要为了代码复用而滥用继承
  • 优先考虑组合关系而不是继承关系
  • 遵循里氏替换原则

更新日志 (Changelog)

  • 2026-04-05: 体系化整合 Java 面向对象三大特性
  • 2026-10-20: 扩展内容,添加的结构、构造器、封装实现、继承机制、多态深入理解和实际应用案例。