面向过程 vs 面向对象
对比维度 | 面向过程(POP) | 面向对象(OOP) |
---|---|---|
编程思维 | 按步骤执行程序逻辑 | 把问题抽象成"对象",通过对象之间交互解决问题 |
示例 | 自己动手做小碗汤(一步步流程) | 去饭店点小碗汤(调用对象的功能) |
优缺点 | 简单直接,但难维护、复用性低 | 模块化、可复用、可扩展,更贴近现实世界 |
OOP(Object Oriented Programming)在底层仍是面向过程,只是做了封装与抽象,让代码更易用、更结构化。
类(Class)
类是对象的模板,描述对象的属性(字段)与行为(方法)
组成部分:
- 字段(Field) :描述对象的状态,如
name
、age
、sex
- 方法(Method) :描述对象的行为,如
eat()
、sleep()
- 构造方法(Constructor):用于创建对象时初始化数据
示例代码:
java
public class Person {
private String name;
private int age;
private int sex;
private void eat() {}
private void sleep() {}
private void dadoudou() {}
}
Java 默认会自动生成一个无参构造方法 :
public Person() {}
,即使代码里没写。
创建对象(new 关键字)
java
Person person = new Person();
-
使用
new
时,会在堆内存中为对象分配空间。 -
程序必须通过
main()
方法启动,可以放在当前类或另一个类中。 -
实际开发中通常使用独立的测试类,例如:
javapublic class PersonTest { public static void main(String[] args) { Person person = new Person(); } }
对象初始化的3种方式
方式 | 示例 | 特点 |
---|---|---|
1. 直接赋值 | person.name = "一成"; |
简单但破坏封装性 |
2. 方法初始化 | person.initialize("一成", 21, 1); |
方法传参赋值,更灵活 |
3. 构造方法初始化 | new Person("一成", 21, 1); |
最常见方式,简洁高效 |
面向过程 注重"怎么做";
面向对象 注重"谁来做"。类是模板,对象是实例;
创建对象用
new
;初始化对象最优方式是------构造方法传参。
Object类
对象比较
1️⃣ hashCode()
-
作用 :返回对象的哈希码(
hash code
),用于散列结构(如HashMap
、HashSet
) -
默认实现:基于对象内存地址计算
如果两个对象通过
equals()
比较相等,则它们的hashCode()
必须相等;反过来不一定成立。 -
自定义实现 (推荐使用
Objects.hash()
):
2️⃣ equals(Object obj)
-
默认实现:比较两个对象的内存地址是否相同
-
自定义比较(按值比较也就是重写之后的比较方法):
javapublic boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof Person1) { Person1 p = (Person1) obj; return this.name.equals(p.getName()) && this.age == p.getAge(); } return false; }
-
注意 :重写
equals()
时,必须同时重写hashCode()
,否则相等的对象进了不同的桶。
方法 | 作用 | 与集合的关系 |
---|---|---|
equals() |
比较内容是否相同 | 判断桶内元素是否重复 |
hashCode() |
决定对象放在哪个桶里 | 决定存储位置 |
对象拷贝
3️⃣ clone()
返回对象的一个副本(浅拷贝),类必须实现 Cloneable
接口,否则会抛出 CloneNotSupportedException
。
- 默认只做浅拷贝(引用对象不复制)。
- 可通过重写实现深拷贝。
对象转字符串
4️⃣ toString()
-
默认实现 :返回
"类名@哈希码的十六进制"
。javapublic String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
-
自定义实现:
javapublic String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
- IDE可自动生成。
- 使用 Lombok 的
@Data
注解可自动生成toString()
。
打印数组时看到如
[I@1b6d3586
,代表数组对象的类型和哈希码。
多线程调度(等待/通知机制)
每个对象都可以作为线程同步锁(监视器),并可使用以下方法协调线程通信。
5️⃣ 核心方法
方法 | 作用 |
---|---|
wait() |
当前线程进入等待状态,直到被 notify() 或 notifyAll() 唤醒 |
notify() |
唤醒一个正在等待该对象锁的线程 |
notifyAll() |
唤醒所有等待该对象锁的线程 |
wait(long timeout) |
等待指定时间(毫秒),超时自动唤醒 |
wait(long timeout, int nanos) |
精确等待到毫秒 + 纳秒级别 |
示例代码(wait/notify
机制)
java
public class WaitNotifyDemo {
public static void main(String[] args) {
Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
System.out.println("线程1:我要等待");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:我被唤醒了");
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("线程2:我要唤醒");
lock.notify();
System.out.println("线程2:我已经唤醒了");
}
}).start();
}
}
执行过程:
- 线程1 进入等待(
wait()
)。 - 线程2 调用
notify()
唤醒线程1。 - 线程1 重新获得锁后继续执行。
小结
功能 | 方法 | 说明 |
---|---|---|
对象比较 | equals() / hashCode() |
比较对象内容与生成哈希值 |
对象复制 | clone() |
实现对象副本(浅拷贝) |
对象描述 | toString() |
输出对象信息 |
线程通信 | wait() / notify() / notifyAll() |
控制线程同步与调度 |