第三阶段:面向对象编程
十一、类和对象
11.1 面向对象和面向过程
| 编程思想 | 核心 | 特点 |
|---|---|---|
| 面向过程 | 强调过程,每一步都要清楚 | 自顶向下,逐步细化 |
| 面向对象 | 强调对象,通过调用对象行为完成功能 | 封装、继承、多态 |
举例:洗衣服
- 面向过程:装水 → 浸泡 → 搓洗 → 漂洗 → 拧干
- 面向对象:衣服对象.放入(洗衣机对象);洗衣机对象.洗(衣服对象)
11.2 类的概述
类(Class):用来描述一类具有共同属性和行为事物的统称,是抽象的。
类的组成:
- 属性:该类事物的状态信息(成员变量)
- 行为:该类事物能做什么(成员方法)
java
// 类的定义
public class Phone {
// 属性(成员变量)
String brand; // 品牌
double price; // 价格
// 行为(成员方法)
public void call(String name) {
System.out.println("给 " + name + " 打电话");
}
public void sendMessage(String message) {
System.out.println("发送消息:" + message);
}
}11.3 对象
对象:类的一个实例,具体存在的、看得见摸得着的实体。
java
public class PhoneTest {
public static void main(String[] args) {
// 创建对象
Phone myPhone = new Phone();
// 访问属性
myPhone.brand = "华为";
myPhone.price = 1999;
// 调用方法
myPhone.call("张三");
myPhone.sendMessage("你好");
}
}11.4 类与对象的关系
类(抽象) 对象(具体)
───────────────────────────────────
手机类 你手上的这台手机
属性:品牌、价格 属性:华为、1999
行为:打电话、发短信 行为:能打电话、能发短信类是对象的抽象,对象是类的实体
11.5 类的定义与应用
java
// 步骤:① 定义类 → ② 编写成员变量 → ③ 编写成员方法
public class Student {
// 成员变量(属性)
String name;
int age;
// 成员方法(行为)
public void study() {
System.out.println(name + " 正在学习");
}
public void sayHello() {
System.out.println("大家好,我是 " + name + ",今年 " + age + " 岁");
}
}十二、封装
封装(Encapsulation):把对象的属性和行为打包在一起,通过访问控制隐藏内部实现细节,只暴露必要接口给外部使用。
12.1 封装的作用
- 隐藏内部实现细节,提高代码安全性
- 控制对成员变量的访问,防止随意修改
- 提高代码的可维护性和可扩展性
- 让对象自己控制自己的状态
12.2 实现封装的关键点
- 成员变量设为
private,防止直接访问 - 提供
public的 getter / setter 方法 - 在方法中进行校验或逻辑处理
12.3 private 关键字
private是一个权限修饰符,代表最小权限- 可以修饰成员变量和成员方法
- 被
private修饰后,只能在本类中访问
java
public class Person {
private String name;
private int age;
// private 修饰的方法只能在本类中调用
private void checkAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄不合法");
}
}
// 提供公共访问方法
public String getName() {
return name;
}
public void setName(String name) {
if (name != null && !name.trim().isEmpty()) {
this.name = name;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
checkAge(age);
this.age = age;
}
}12.4 this 关键字
this 代表当前调用方法的引用。哪个对象调用 this 所在的方法,this 就代表哪个对象。
主要作用:区分同名的局部变量和成员变量
java
public class Student {
private String name;
public void setName(String name) {
// this.name 是成员变量,= 右边的 name 是参数(局部变量)
this.name = name;
}
}12.5 getter / setter 方法
| 方法 | 作用 | 命名规则 |
|---|---|---|
getter | 获取成员变量的值 | getXxx() |
setter | 设置成员变量的值 | setXxx(参数) |
12.6 构造方法
构造方法(Constructor):用来创建对象并初始化成员变量的特殊方法。
特点
- 方法名必须和类名相同
- 没有返回值类型,连
void都不能写 - 创建对象时自动调用
- 可以有多个(重载)
- 构造方法中可以调用其他构造方法:
this(...)必须放在第一行
java
public class Person {
private String name;
private int age;
// 无参构造
public Person() {
this("默认名", 0); // 调用有参构造
}
// 有参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}注意事项
- 如果不写构造方法,Java 自动提供无参构造器
- 一旦写了有参构造,系统不再提供默认无参构造,如需使用需手动写出
- 构造方法不能被
static、final、abstract修饰 - 构造方法不能被继承,但可通过
super()调用父类构造器
12.7 访问权限修饰符一览(补充)
| 修饰符 | 本类 | 同包 | 子类(不同包) | 所有类 |
|---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
| 默认(不写) | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
十三、继承
13.1 继承概述
继承:一个类可以继承另一个类,使用 extends 关键字。
- 被继承的类:父类 / 超类 / 基类
- 继承的类:子类
- 继承后,子类拥有父类中所有非私有成员
好处:
- 提高代码复用性
- 使类与类之间产生了关系(多态的前提)
java
class 父类 {
// ...
}
class 子类 extends 父类 {
// ...
}13.2 继承演示
java
// 父类
public class Person {
String name;
int age;
public void eat() {
System.out.println("吃东西...");
}
public void sleep() {
System.out.println("睡觉...");
}
}
// 子类
public class Teacher extends Person {
double salary; // 子类独有属性
public void teach() {
System.out.println("教书...");
}
}
// 子类
public class Student extends Person {
// 直接继承父类的 name、age、eat()、sleep()
}注意:Java 是单继承的,一个类只能继承一个直接父类,且需满足 is-a 关系(Student is a Person)。
13.3 成员访问规则
- 父类的构造方法不能被继承
- 父类的 private 成员可以被子类继承,但不能直接访问
- 访问成员时:先在子类中找 → 找不到再去父类中找
13.4 方法重写(Override)
重写:子类中出现与父类一模一样的方法(返回值类型、方法名、参数列表都相同)。
java
class Fu {
public void method() {
System.out.println("Fu method");
}
}
class Zi extends Fu {
@Override
public void method() {
System.out.println("Zi method");
}
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method(); // 输出:Zi method
}
}重写注意事项
- 必须发生在父子类之间
- 方法签名(返回值、方法名、参数列表)必须完全相同
- 子类方法访问权限不能低于父类(
public > protected > 默认 > private) - 建议使用
@Override注解校验,提高可读性和安全性
13.5 this 与 super 关键字
| 关键字 | 含义 | 可以访问 |
|---|---|---|
this | 当前对象的引用 | 本类的成员属性、方法、构造方法 |
super | 父类对象的引用 | 父类的成员属性、方法、构造方法 |
java
public class Student extends Person {
public Student() {
super(); // 调用父类无参构造(默认隐含,可省略)
System.out.println("Student 构造器");
}
public Student(String name, int age) {
super(name, age); // 调用父类有参构造
}
public void show() {
super.eat(); // 调用父类方法
this.study(); // 调用本类方法
}
}13.6 类加载过程
有继承关系时,类的加载和对象创建顺序:
java
public class Person {
private String name;
private int age;
static {
System.out.println("Person 静态块 - 01");
}
{
System.out.println("Person 对象块 - 02");
}
public Person() {
System.out.println("Person 构造方法 - 03");
}
}
public class Student extends Person {
static {
System.out.println("Student 静态块 - 01");
}
{
System.out.println("Student 对象块 - 02");
}
public Student() {
super();
System.out.println("Student 构造方法 - 03");
}
}执行结果:
Person 静态块 - 01
Student 静态块 - 01
Person 对象块 - 02
Person 构造方法 - 03
Student 对象块 - 02
Student 构造方法 - 03总结:
- 父类静态块 → 子类静态块(类加载时执行,仅一次)
- 父类对象块 → 父类构造器
- 子类对象块 → 子类构造器
13.7 Object 类(补充)
Object 是所有类的根父类(超类)。每个类都直接或间接继承自 Object。
常用方法:
| 方法 | 说明 |
|---|---|
equals(Object obj) | 判断对象是否"相等"(默认比较地址) |
hashCode() | 返回哈希码值 |
toString() | 返回字符串表示(默认:类名@地址) |
finalize() | 垃圾回收前调用(不推荐使用) |
java
public class ObjectDemo {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
System.out.println(obj1.toString()); // java.lang.Object@15db9742
System.out.println(obj1.equals(obj2)); // false(比较地址)
System.out.println(obj1.hashCode()); // 哈希码
}
}十四、抽象类(补充)
14.1 抽象类与抽象方法
使用 abstract 关键字修饰的类和方法。
java
// 抽象类:不能被实例化
public abstract class Animal {
private String name;
// 抽象方法:只有声明,没有方法体
public abstract void makeSound();
// 普通方法
public void sleep() {
System.out.println("睡觉...");
}
}14.2 抽象类的特点
- 抽象类不能创建对象(不能
new) - 抽象方法不能有方法体
- 子类必须重写所有抽象方法,否则子类也必须是抽象类
- 抽象类中可以有成员变量、构造方法、普通方法
java
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}十五、接口
15.1 概述
接口是 Java 中的一种引用类型,是方法的"集合"。
java
public interface 接口名称 {
// 常量(JDK 7 及以前)
// 抽象方法(JDK 7 及以前)
// 默认方法(JDK 8)
// 静态方法(JDK 8)
// 私有方法(JDK 9)
}15.2 接口与抽象类的区别
| 抽象类 | 接口 | |
|---|---|---|
| 关键字 | abstract class | interface |
| 多继承 | 单继承 | 可多实现 |
| 构造方法 | 有 | 无 |
| 成员变量 | 可以有各种类型 | 只能是 public static final 常量 |
| 方法 | 可抽象可具体 | 抽象方法、默认方法、静态方法 |
15.3 接口的实现
java
public interface IA {
void show1();
}
public interface IB {
void show2();
}
// 类可以实现多个接口
public class Zi implements IA, IB {
@Override
public void show1() {
System.out.println("实现 show1");
}
@Override
public void show2() {
System.out.println("实现 show2");
}
}
// 同时继承和实现
public class Zi extends Fu implements IA, IB {
// 先继承,后实现
}15.4 接口成员访问特点
| 成员类型 | 访问特点 |
|---|---|
| 常量 | 接口直接使用 |
| 抽象方法 | 实现类必须重写 |
| 默认方法(JDK 8) | 实现类继承,可直接调用 |
| 静态方法(JDK 8) | 仅接口直接调用,实现类不可继承 |
| 私有方法(JDK 9) | 仅在接口内部调用 |
十六、多态
16.1 多态概述
多态:同一行为,对于不同对象具有多种表现形式。
java
// 父类引用指向子类对象
父类类型 变量名 = new 子类对象();16.2 多态的形式
java
// 1. 普通父类多态
Person p = new Student();
// 2. 抽象父类多态
Animal a = new Dog();
// 3. 父接口多态
Runnable r = new Thread();16.3 多态的应用
形参多态(最常用):
java
public void feed(Animal animal) { // 可以接收任何 Animal 子类对象
animal.eat();
}返回值多态:
java
public Animal getAnimal() {
return new Dog(); // 返回子类对象
}16.4 引用类型转换
java
// 向上转型(自动)
Animal a = new Dog();
// 向下转型(强制,需确保实际类型匹配)
Dog d = (Dog) a;
// 使用 instanceof 判断类型
if (a instanceof Dog) {
Dog dog = (Dog) a;
}多态的弊端:无法访问子类独有的方法或成员变量。
java
Animal a = new Dog();
// a.wagTail(); // 编译错误!Animal 类型没有 wagTail 方法
Dog d = (Dog) a;
d.wagTail(); // 向下转型后可以访问第三阶段小结:本阶段学习了面向对象三大特性——封装(隐藏实现、getter/setter)、继承(代码复用、方法重写)和多态(父类引用指向子类对象)。同时还学习了抽象类和接口这两个重要概念。面向对象是 Java 的核心思想,请务必理解透彻。