前言
面向对象(OOP)是基于 "类" 和 "对象" 的编程思想,核心特性为封装、继承、多态,旨在将现实世界的事物抽象为程序中的类和对象,提高代码的复用性和可维护性。
文章目录
-
- 前言
- [1. 类与对象](#1. 类与对象)
-
- [1.1 核心概念](#1.1 核心概念)
- [1.2 创建与使用](#1.2 创建与使用)
- [1.3 代码示例](#1.3 代码示例)
- [1.4 内存规则](#1.4 内存规则)
- 1.5注意事项
- [2. 方法](#2. 方法)
-
- [2.1 方法定义格式](#2.1 方法定义格式)
- [2.2 方法调用格式](#2.2 方法调用格式)
- [2.3 方法注意事项](#2.3 方法注意事项)
- [2.4 方法重载(Overload)](#2.4 方法重载(Overload))
-
- [2.4.1 核心定义](#2.4.1 核心定义)
- [2.4.2 核心作用](#2.4.2 核心作用)
- [2.4.3 代码示例](#2.4.3 代码示例)
- [2.5 构造方法](#2.5 构造方法)
-
- [2.5.1 核心作用](#2.5.1 核心作用)
- [2.5.2 核心规则](#2.5.2 核心规则)
- [2.5.3 代码示例](#2.5.3 代码示例)
- [3. 封装(三大特性之一)](#3. 封装(三大特性之一))
-
- [3.1 核心思想](#3.1 核心思想)
- [3.2 实现步骤](#3.2 实现步骤)
- [3.3 标准 JavaBean(实体类规范)](#3.3 标准 JavaBean(实体类规范))
- [3.4 代码示例](#3.4 代码示例)
- [3.5 应用场景](#3.5 应用场景)
- [3.6 注意事项](#3.6 注意事项)
- [4. 继承(三大特性之二)](#4. 继承(三大特性之二))
-
- [4.1 核心概念](#4.1 核心概念)
- [4.2 语法格式](#4.2 语法格式)
- [4.3 继承的核心特点](#4.3 继承的核心特点)
- [4.4 this 与 super 关键字(核心区别)](#4.4 this 与 super 关键字(核心区别))
- [4.5 代码示例](#4.5 代码示例)
- [4.5 方法重写(Override,核心重点)](#4.5 方法重写(Override,核心重点))
-
- [4.5.1 核心概念](#4.5.1 核心概念)
- [4.5.2 方法重写的满足条件](#4.5.2 方法重写的满足条件)
- [4.5.3 代码示例](#4.5.3 代码示例)
- [4.5.4 构造方法的继承规则](#4.5.4 构造方法的继承规则)
- [4.5.5 应用场景](#4.5.5 应用场景)
- [5. 多态(三大特性之三)](#5. 多态(三大特性之三))
-
- [5.1 核心概念](#5.1 核心概念)
- [5.2 多态的前提](#5.2 多态的前提)
- [5.3 语法格式](#5.3 语法格式)
- [5.4 代码示例](#5.4 代码示例)
- [5.5 多态的调用规则](#5.5 多态的调用规则)
- [5.6 类型转换(多态的核心操作)](#5.6 类型转换(多态的核心操作))
-
- [5.6.1 向上转型(自动转换,安全)](#5.6.1 向上转型(自动转换,安全))
- [5.6.2 向下转型(强制转换,需校验)](#5.6.2 向下转型(强制转换,需校验))
- [5.6.3 instanceof 关键字](#5.6.3 instanceof 关键字)
- [5.7 多态的优缺点](#5.7 多态的优缺点)
- [5.8 应用场景](#5.8 应用场景)
1. 类与对象
1.1 核心概念
-
类:对现实世界中一类具有共同属性和行为的事物的抽象描述,是对象的 "模板"。
-
组成:属性(成员变量)+ 行为(成员方法)。
-
属性:类中方法外的变量,描述事物的特征(如手机的品牌、价格)。
-
行为:类中的成员方法(无
static关键字),描述事物的操作(如手机打电话)。
-
-
对象:类的实例化结果,是客观存在的具体实体(如一部具体的手机)。
-
类与对象的关系:类是抽象描述,对象是具体实例。
1.2 创建与使用
java
// 1. 定义类
public class 类名 {
// 成员变量(属性)
private 数据类型 变量名;
// 构造方法
public 类名() {} // 无参构造
public 类名(参数列表) {} // 带参构造
// 成员方法(行为)
public 返回值类型 方法名() {
// 方法体
}
}
// 2. 创建对象(new关键字必不可少)
类名 对象名 = new 类名(实参);
// 3. 使用对象
对象名.成员变量; // 访问属性
对象名.成员方法(); // 调用方法
1.3 代码示例
java
// 1. 定义学生类(模板)
public class Student {
// 成员属性
String name; // 姓名
String studentId; // 学号
int age; // 年龄
String className; // 班级
double score; // 成绩
// 成员方法(行为)
// 上课方法
public void attendClass() {
System.out.println(name + "(学号:" + studentId + ")在" + className + "班上课,认真听讲");
}
// 考试方法
public void takeExam() {
System.out.println(name + "参加考试,目前成绩:" + score + "分");
}
// 交作业方法
public void handInHomework() {
System.out.println(name + "按时交作业,态度认真");
}
// 查成绩方法
public void checkScore() {
System.out.println(name + "的当前成绩为:" + score + "分");
}
}
// 2. 测试类(创建对象,调用方法)
public class StudentTest {
public static void main(String[] args) {
// 创建对象1:张三
Student zhangsan = new Student();
// 给对象赋值(属性初始化)
zhangsan.name = "张三";
zhangsan.studentId = "2024001";
zhangsan.age = 18;
zhangsan.className = "高一(1)班";
zhangsan.score = 90.5;
// 调用对象的方法
zhangsan.attendClass();
zhangsan.takeExam();
System.out.println("-------------------");
// 创建对象2:李四
Student lisi = new Student();
lisi.name = "李四";
lisi.studentId = "2024002";
lisi.age = 17;
lisi.className = "高一(2)班";
lisi.score = 85.0;
lisi.attendClass();
lisi.handInHomework();
}
}
1.4 内存规则
- 对象(包括成员变量)存储在 堆内存,堆内存中的对象有默认初始化值(String→null、int→0、double→0.0、boolean→false)。
- 方法(成员方法、静态方法)存储在 方法区,所有对象共享同一份方法代码,调用时方法入栈执行。
- 局部变量(方法内的变量)存储在 栈内存,无默认值,必须初始化后才能使用,方法执行完毕后栈内存释放。
1.5注意事项
- 对象必须通过
new关键字创建,仅声明引用(如Phone phone = null;)不会创建对象,调用方法会报空指针异常(NullPointerException)。 - 成员变量与局部变量同名时,方法内优先使用局部变量(就近原则),若要访问成员变量,需用
this.变量名。
2. 方法
方法是程序中最小的执行单元,用于封装特定功能,实现代码复用,避免重复编写。
2.1 方法定义格式
-
无参无返回值方法(仅执行操作,不返回结果)
java// 格式 public static void 方法名() { // 方法体:具体功能代码 } // 示例:打印欢迎语 public static void printWelcome() { System.out.println("Hello Java!"); } -
带参无返回值方法(接收参数,执行操作,不返回结果)
java// 格式 public static void 方法名(参数类型1 参数名1, 参数类型2 参数名2) { // 方法体:使用参数执行操作 } // 示例:打印指定姓名的欢迎语 public static void printWelcome(String name) { System.out.println("Welcome " + name + "!"); } -
带返回值方法(接收参数,执行操作,返回结果给调用者)
java// 格式 public static 返回值类型 方法名(参数列表) { // 方法体:执行操作 return 结果; // 返回值,类型必须与定义的返回值类型一致 } // 示例:计算两个整数的和,返回结果 public static int add(int a, int b) { int sum = a + b; return sum; // 返回sum,类型为int,与方法定义一致 }
2.2 方法调用格式
| 方法类型 | 调用格式 | 示例 |
|---|---|---|
| 无参无返回值 | 方法名(); | printWelcome(); |
| 带参无返回值 | 方法名(实参1, 实参2); | printWelcome("李四"); |
| 带返回值 | 返回值类型 变量名 = 方法名(实参); | int sum = add(10, 20); |
2.3 方法注意事项
-
方法不能嵌套定义:方法只能定义在类中,不能定义在另一个方法内部。
java// 错误示例 public static void method1() { // 方法嵌套,编译报错 public static void method2() { } } -
方法必须先定义,后调用(顺序不能颠倒),除非是递归调用。
-
调用方法时,实参的数量、类型、顺序必须与形参完全匹配,否则编译报错。
-
void表示无返回值,可省略return,也可写return;(后面不能跟任何数据),否则编译报错。java// 正确示例 public static void method() { return; // 无返回值,仅结束方法 } // 错误示例 public static void method() { return 100; // void方法不能返回数据 } -
带返回值的方法,所有分支必须有return语句(否则编译报错)。
java// 错误示例(缺少else分支的return) public static int getMax(int a, int b) { if (a > b) { return a; } } // 正确示例 public static int getMax(int a, int b) { if (a > b) { return a; } else { return b; } }
2.4 方法重载(Overload)
2.4.1 核心定义
同一类中,方法名相同 ,但 参数列表不同(参数个数不同、参数类型不同、参数顺序不同)的多个方法,与返回值类型、访问修饰符无关。
2.4.2 核心作用
实现"同名不同功",简化调用,例如:add 方法可同时实现两个int求和、两个double求和,无需定义 addInt、addDouble 等不同方法。
2.4.3 代码示例
java
// 正确示例
public class OverloadDemo {
// 重载1:两个int参数
public static int add(int a, int b) {
return a + b;
}
// 重载2:两个double参数(类型不同)
public static double add(double a, double b) {
return a + b;
}
// 重载3:三个int参数(个数不同)
public static int add(int a, int b, int c) {
return a + b + c;
}
public static void main(String[] args) {
System.out.println(add(10, 20)); // 调用重载1
System.out.println(add(10.5, 20.5)); // 调用重载2
System.out.println(add(1, 2, 3)); // 调用重载3
}
}
// 错误示例(不构成重载)
public class OverloadErrorDemo {
// 错误1:仅返回值不同,不构成重载
public static int add(int a, int b) { return a + b; }
public static double add(int a, int b) { return a + b; }
// 错误2:仅参数名不同,不构成重载
public static int add(int x, int y) { return x + y; }
}
2.5 构造方法
2.5.1 核心作用
创建对象(new 关键字调用)+ 初始化成员变量,不能用于调用其他功能。
2.5.2 核心规则
- 方法名与 类名完全一致(大小写也必须一致),无返回值类型(不能写void)。
- 若未自定义构造方法,JVM会自动生成一个 无参构造方法(默认构造),无方法体。
- 一旦自定义构造方法(无参/带参),JVM不再提供默认无参构造,若需使用无参构造,需手动编写。
- 构造方法支持重载(无参构造、带参构造可同时存在)。
- 构造方法不能手动调用,只能通过
new 类名()自动调用。
2.5.3 代码示例
java
public class Student {
private String name;
private int age;
// 1. 无参构造(手动编写)
public Student() {
// 可手动初始化默认值
this.name = "姓名";
this.age = 18;
}
// 2. 带参构造(重载,初始化时赋值)
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 3. 带参构造(重载,仅初始化姓名)
public Student(String name) {
this.name = name;
this.age = 20;
}
public static void main(String[] args) {
Student s1 = new Student(); // 调用无参构造
Student s2 = new Student("张三", 18); // 调用带参构造
Student s3 = new Student("李四"); // 调用重载的带参构造
}
}
3. 封装(三大特性之一)
3.1 核心思想
隐藏对象的内部实现细节(私有化成员变量),仅对外提供公共的访问方式(get/set方法),控制属性的读写权限,提高代码的安全性、可维护性。
通俗理解:像手机一样,我们不需要知道内部芯片、电路的工作原理,只需通过屏幕、按键(公共接口)操作即可。
3.2 实现步骤
- 将类的成员变量用 private 修饰(私有化),禁止外部直接访问。
- 为每个私有化成员变量,提供 public 的
getXxx()方法(获取属性值)和setXxx()方法(设置属性值)。 - 在
setXxx()方法中添加数据校验逻辑,避免非法值赋值。
3.3 标准 JavaBean(实体类规范)
JavaBean 是封装的典型应用,用于描述实体(如学生、用户、商品),需满足以下4个条件:
- 类名见名知意(如 Student、User、Goods),采用驼峰命名法(首字母大写,后续单词首字母大写)。
- 所有成员变量用 private 修饰。
- 提供无参构造方法(必须有,否则影响框架使用)。
- 为每个成员变量提供完整的 get/set 方法。
3.4 代码示例
java
// 标准JavaBean:Person类(封装实现)
public class Person {
// 1. 私有化成员变量
private String name; // 姓名
private int age; // 年龄
private double height; // 身高
// 2. 无参构造(必须有)
public Person() {}
// 3. 带参构造(可选,方便初始化)
public Person(String name, int age, double height) {
this.name = name;
this.setAge(age); // 调用setter,复用校验逻辑
this.height = height;
}
// 4. get/set方法(公共访问接口)
public String getName() {
return name; // 获取姓名
}
public void setName(String name) {
this.name = name; // 设置姓名
}
public int getAge() {
return age; // 获取年龄
}
public void setAge(int age) {
// 数据校验:年龄必须在0-150之间,否则赋值默认值18
if (age < 0 || age > 150) {
System.out.println("年龄不合法,默认赋值18");
this.age = 18;
} else {
this.age = age;
}
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
// 行为方法
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",身高:" + height + "cm");
}
}
// 测试类
public class PersonTest {
public static void main(String[] args) {
Person p = new Person("王五", 200, 175.5); // 年龄不合法
p.showInfo(); // 输出:姓名:王五,年龄:18,身高:175.5cm
p.setAge(25); // 合法年龄
p.showInfo(); // 输出:姓名:王五,年龄:25,身高:175.5cm
// 无法直接访问私有属性(编译报错)
// System.out.println(p.age);
}
}
3.5 应用场景
- 所有实体类(JavaBean)的属性私有化,如学生、用户、订单、商品等。
- 需要控制属性读写权限的场景:如只读属性(仅提供get,不提供set)、只写属性(仅提供set)。
- 需要对属性赋值进行校验的场景:如年龄、手机号、邮箱格式校验。
3.6 注意事项
- private 修饰的成员,仅当前类可直接访问,子类、外部类均不能直接访问,只能通过 get/set 访问。
- get 方法的返回值类型,必须与对应成员变量的类型一致;set 方法的参数类型,必须与对应成员变量的类型一致。
4. 继承(三大特性之二)
4.1 核心概念
子类(派生类)通过 extends 关键字,继承父类(基类)的非私有属性和方法,实现代码复用,建立类之间的层级关系(如"学生"继承"人","猫"继承"动物")。
通俗理解:儿子继承父亲的财产(非私有属性)和技能(非私有方法),同时可以有自己的特有财产和技能。
4.2 语法格式
java
// 父类(基类):被继承的类
class 父类名 {
// 非私有属性和方法
}
// 子类(派生类):继承父类的类
class 子类名 extends 父类名 {
// 子类特有属性和方法
}
4.3 继承的核心特点
- Java 仅支持 单继承 :一个子类只能有一个直接父类(避免多继承的歧义),但支持 多层继承(如 A→B→C,C继承B,B继承A)。
- 所有类默认继承
java.lang.Object类(根类),若一个类没有显式继承其他类,默认继承 Object。 - 子类可以继承父类的 非私有成员(非private的成员变量、成员方法),不能继承父类的构造方法。
- 父类的私有成员(private),子类可以继承 (占用内存),但无法直接访问,需通过父类提供的 public 方法(get/set)访问。
- 子类可以拥有自己的特有属性和方法,实现功能扩展。
4.4 this 与 super 关键字(核心区别)
| 关键字 | 含义 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
|---|---|---|---|---|
| this | 当前对象(子类对象) | this.变量名(优先访问子类成员) | this.方法名()(优先访问子类方法) | this()(调用子类自身构造) |
| super | 父类对象 | super.变量名(访问父类成员) | super.方法名()(访问父类方法) | super()(调用父类构造,默认存在) |
4.5 代码示例
java
// 父类:人类(基类)
public class Person {
// 非私有成员变量
protected String name; // protected:子类可直接访问
private int age; // private:子类不能直接访问
// 父类无参构造
public Person() {
System.out.println("父类无参构造执行");
}
// 父类带参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("父类带参构造执行");
}
// 父类非私有方法
public void eat() {
System.out.println(name + "吃饭");
}
// 父类public方法:供子类访问私有成员age
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 子类:学生类(继承Person)
public class Student extends Person {
// 子类特有属性
private double score; // 成绩
// 子类无参构造
public Student() {
// 默认调用父类无参构造:super();(可省略)
System.out.println("子类无参构造执行");
}
// 子类带参构造
public Student(String name, int age, double score) {
super(name, age); // 手动调用父类带参构造(必须在第一行)
this.score = score;
System.out.println("子类带参构造执行");
}
// 子类特有方法
public void study() {
// 访问父类protected成员name(直接访问)
// 访问父类private成员age(通过getter访问)
System.out.println(name + "学习,年龄:" + getAge() + ",成绩:" + score);
}
// 重写父类方法
@Override
public void eat() {
super.eat(); // 调用父类的eat方法
System.out.println(name + "在食堂吃饭"); // 子类扩展逻辑
}
// get/set(子类特有属性)
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
// 测试类
public class ExtendsTest {
public static void main(String[] args) {
Student s = new Student("赵六", 20, 95.5);
s.eat(); // 调用重写后的方法
s.study(); // 调用子类特有方法
System.out.println("父类私有age:" + s.getAge()); // 访问父类私有成员
}
}
4.5 方法重写(Override,核心重点)
4.5.1 核心概念
子类继承父类后,若父类的方法无法满足子类的需求,子类可以定义一个与父类方法名、参数列表、返回值类型完全一致的方法,覆盖父类的方法,称为方法重写。
核心作用:实现"子类个性化",例如"人"的 eat() 方法是"吃饭","学生"的 eat() 方法可以重写为"在食堂吃饭"。
4.5.2 方法重写的满足条件
- 有继承关系(子类继承父类)。
- 方法名、参数列表、返回值类型完全一致(JDK7+支持协变返回值:子类返回值可以是父类返回值的子类)。
- 子类方法的访问权限 ≥ 父类方法的访问权限(如父类是 protected,子类可以是 protected 或 public;父类是 public,子类必须是 public)。
- 父类方法不能是 private(private方法子类无法继承,无法重写)。
- 建议添加
@Override注解(重写校验注解),若不符合重写条件,编译报错,提高代码可读性。
4.5.3 代码示例
java
// 父类
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
protected void run() {
System.out.println("动物跑步");
}
private void sleep() {
System.out.println("动物睡觉");
}
}
// 子类
public class Cat extends Animal {
// 正确重写:满足所有条件
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 正确重写:子类权限 ≥ 父类(protected → public)
@Override
public void run() {
System.out.println("猫快速跑步");
}
// 错误示例1:父类方法是private,无法重写(编译报错)
@Override
private void sleep() {
System.out.println("猫睡觉");
}
// 错误示例2:参数列表不同,不构成重写(编译报错)
@Override
public void eat(String food) {
System.out.println("猫吃" + food);
}
// 错误示例3:访问权限低于父类(public → protected,编译报错)
@Override
protected void eat() {
System.out.println("猫吃鱼");
}
}
4.5.4 构造方法的继承规则
- 子类构造方法执行时,第一行默认调用父类无参构造 (
super();),无论是否显式书写,该语句都存在。 - 若父类没有无参构造(仅自定义了带参构造),子类必须在构造方法的第一行,手动调用父类带参构造 (
super(实参);),否则编译报错。 this()(调用子类自身构造)和super()(调用父类构造),不能同时出现在子类构造方法的第一行,只能二选一。
4.5.5 应用场景
- 多个类有共同的属性和方法时,提取父类,子类继承父类,减少代码冗余(如学生、老师、管理员,都继承"人"类)。
- 子类需要修改父类方法的逻辑时,通过方法重写实现个性化(如动物的"叫"方法,猫重写为"喵喵叫",狗重写为"汪汪叫")。
5. 多态(三大特性之三)
5.1 核心概念
多态:同一行为(方法调用),在不同对象上表现出不同的形式。例如:"eat()"方法,猫调用是"吃鱼",狗调用是"吃骨头",本质是方法重写的体现。
5.2 多态的前提
- 有继承/实现关系(子类继承父类,或实现类实现接口)。
- 有方法重写(核心,无重写则多态无意义)。
- 有父类/接口引用指向子类/实现类对象(向上转型,核心格式)。
5.3 语法格式
java
// 格式1:父类引用指向子类对象(继承关系)
父类类型 变量名 = new 子类类型();
// 格式2:接口引用指向实现类对象(实现关系)
接口类型 变量名 = new 实现类类型();
5.4 代码示例
java
// 父类:动物
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
public void run() {
System.out.println("动物跑步");
}
}
// 子类1:猫
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void run() {
System.out.println("猫轻盈地跑步");
}
// 子类特有方法
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
// 子类2:狗
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void run() {
System.out.println("狗快速地跑步");
}
}
// 测试类
public class PolymorphismTest {
public static void main(String[] args) {
// 1. 向上转型(多态核心格式)
Animal a1 = new Cat(); // 父类引用指向猫对象
Animal a2 = new Dog(); // 父类引用指向狗对象
// 2. 多态调用方法:编译看左边,运行看右边
a1.eat(); // 编译看Animal(有eat方法),运行看Cat → 猫吃鱼
a1.run(); // 运行看Cat → 猫轻盈地跑步
a2.eat(); // 运行看Dog → 狗吃骨头
a2.run(); // 运行看Dog → 狗快速地跑步
// 3. 多态的弊端:无法直接调用子类特有方法(编译报错)
// a1.catchMouse(); // 错误:Animal类没有catchMouse方法
// 4. 解决弊端:向下转型(强制转换)
if (a1 instanceof Cat) { // 先判断类型,避免转换异常
Cat c = (Cat) a1; // 强制转换为Cat类型
c.catchMouse(); // 调用子类特有方法 → 猫抓老鼠
}
// 5. JDK14+新特性:instanceof + 强转一步完成(简化代码)
if (a1 instanceof Cat cat) {
cat.catchMouse(); // 直接使用cat调用方法
}
}
}
5.5 多态的调用规则
-
成员变量:编译看左边(父类),运行看左边(父类)。
java// 示例 class Fu { int num = 10; } class Zi extends Fu { int num = 20; } public class Test { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); // 输出10(编译/运行都看左边Fu) } } -
成员方法:编译看左边(父类),运行看右边(子类)(核心,因为方法重写)。解释:编译时,JVM检查父类是否有该方法,有则编译通过;运行时,JVM执行子类重写后的方法。
5.6 类型转换(多态的核心操作)
5.6.1 向上转型(自动转换,安全)
- 格式:子类对象 → 父类引用(
父类类型 变量名 = new 子类类型();)。 - 特点:自动完成,安全(子类是父类的"子集"),但丢失子类特有方法和属性。
- 本质:多态的核心格式,是向下转型的前提。
5.6.2 向下转型(强制转换,需校验)
- 格式:父类引用 → 子类对象(
子类类型 变量名 = (子类类型) 父类引用;)。 - 特点:强制完成,不安全(可能引发 ClassCastException 类型转换异常),用于调用子类特有方法。
- 必须先使用
instanceof关键字校验类型,确认父类引用指向的是该子类对象,再进行转换。
5.6.3 instanceof 关键字
作用:校验一个对象是否是某个类(或其子类)的实例,返回 boolean 值(true/false),用于避免向下转型异常。
java
// 格式
对象名 instanceof 类名/接口名
// 示例(结合向下转型)
Animal a = new Cat();
if (a instanceof Cat) {
Cat c = (Cat) a; // 安全转换
} else if (a instanceof Dog) {
Dog d = (Dog) a;
} else {
System.out.println("无法转换");
}
5.7 多态的优缺点
| 优点 | 缺点 |
|---|---|
| 提高代码扩展性:父类/接口作为方法参数,可接收所有子类/实现类对象,无需修改方法代码。 | 无法直接调用子类特有方法和属性,需向下转型。 |
| 降低代码耦合度:依赖抽象(父类/接口),不依赖具体实现(子类)。 | 向下转型可能引发类型转换异常,需用 instanceof 校验。 |
| 简化代码调用:统一调用父类方法,不同对象自动执行对应逻 | 成员变量调用不灵活(始终访问父类变量)。 |
5.8 应用场景
- 方法参数统一为父类/接口类型,实现"一个方法接收多种对象"(如定义
feed(Animal a)方法,可接收 Cat、Dog 等所有动物对象)。 - 框架开发(如 Spring),通过多态实现解耦,便于扩展(如接口的不同实现类,可切换使用)。