JavaSE面向对象(上)
面向过程 vs 面向对象
对比维度 | 面向过程(POP) | 面向对象(OOP) |
---|---|---|
编程思维 | 按步骤执行程序逻辑 | 把问题抽象成“对象”,通过对象之间交互解决问题 |
示例 | 自己动手做小碗汤(一步步流程) | 去饭店点小碗汤(调用对象的功能) |
优缺点 | 简单直接,但难维护、复用性低 | 模块化、可复用、可扩展,更贴近现实世界 |
OOP(Object Oriented Programming)在底层仍是面向过程,只是做了封装与抽象,让代码更易用、更结构化。
类(Class)
类是对象的模板,描述对象的属性(字段)与行为(方法)
组成部分:
- 字段(Field):描述对象的状态,如
name
、age
、sex
- 方法(Method):描述对象的行为,如
eat()
、sleep()
- 构造方法(Constructor):用于创建对象时初始化数据
示例代码:
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 关键字)
Person person = new Person();
-
使用
new
时,会在堆内存中为对象分配空间。 -
程序必须通过
main()
方法启动,可以放在当前类或另一个类中。 -
实际开发中通常使用独立的测试类,例如:
public 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)
-
默认实现:比较两个对象的内存地址是否相同
-
自定义比较(按值比较也就是重写之后的比较方法):
public 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()
-
默认实现:返回
"类名@哈希码的十六进制"
。public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
-
自定义实现:
public 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
机制)
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() | 控制线程同步与调度 |