1. 项目概述
"模块七--面向对象-尚硅谷Javase笔记总结"这个标题看似简单,却蕴含着一个Java学习者从入门到进阶的关键转折点。作为一名在Java领域摸爬滚打多年的开发者,我深知面向对象编程(OOP)是Java语言的核心灵魂,也是区分"会写代码"和"懂编程思想"的重要分水岭。
这份笔记总结来自尚硅谷的JavaSE课程模块七,系统性地梳理了面向对象的核心概念、实现机制和设计思想。不同于零散的知识点堆砌,它按照"概念理解->语法掌握->设计应用"的认知路径组织内容,特别适合已经掌握Java基础语法,正准备向中高级进阶的学习者。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心内容解析
2.1 面向对象四大特性深度剖析
2.1.1 封装(Encapsulation)的工程价值
封装不仅仅是简单的private修饰符使用。在实际项目中,我常用以下模式实现业务封装:
java复制// 银行账户的经典封装示例
public class BankAccount {
private double balance;
// 存款方法加入业务校验
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("存款金额必须大于零");
}
this.balance += amount;
logTransaction("DEPOSIT", amount);
}
// 私有方法记录交易日志
private void logTransaction(String type, double amount) {
// 实现日志记录逻辑
}
}
经验之谈:封装时建议采用"宽进严出"原则,对外提供简洁的API接口,内部实现可以复杂但对外透明。我曾见过因封装不当导致属性被随意修改引发的资金计算错误,教训深刻。
2.1.2 继承(Inheritance)的合理使用
继承是把双刃剑。在电商系统开发中,我曾重构过一个糟糕的继承体系:
java复制// 错误示范:过度使用继承
class Product {
// 通用商品属性
}
class Book extends Product {
// 书籍特有属性
}
class Electronic extends Product {
// 电子产品特有属性
}
class MobilePhone extends Electronic {
// 手机特有属性
}
问题在于:当需要支持"电子书"这类跨分类商品时,继承体系就会崩溃。更合理的做法是:
java复制// 改进方案:组合优于继承
class Product {
// 基础属性
List<ProductCategory> categories;
}
interface ProductCategory {
// 分类行为定义
}
class BookCategory implements ProductCategory { /*...*/ }
class ElectronicCategory implements ProductCategory { /*...*/ }
2.2 Java面向对象语法精要
2.2.1 类与对象的本质区别
很多初学者分不清类和对象的区别。用汽车工厂类比:
- 类就像汽车设计图纸(包含所有属性和方法定义)
- 对象是按图纸生产的实际汽车(拥有具体属性值)
内存角度分析:
java复制Person p1 = new Person(); // 在堆内存创建实例
Person p2 = p1; // 引用传递,不创建新对象
我曾遇到过一个内存泄漏案例:因为不理解对象引用机制,在循环中不断new对象却没有释放,导致OOM。
2.2.2 构造方法的进阶用法
除了默认构造方法,这些技巧很实用:
java复制public class Student {
// 链式构造方法
public Student() {
this("未知", 0); // 调用全参构造
}
public Student(String name) {
this(name, 0);
}
public Student(String name, int age) {
// 实际初始化逻辑
}
}
在Spring框架中,构造器注入正是基于这种机制实现的依赖注入。
2.3 多态与接口的实战应用
2.3.1 多态的三要素实现
编译时类型与运行时类型的分离是多态的核心。支付系统案例:
java复制interface Payment {
void pay(BigDecimal amount);
}
class Alipay implements Payment { /*...*/ }
class WechatPay implements Payment { /*...*/ }
// 使用多态
Payment payment = getPaymentMethod();
payment.pay(100.00); // 实际调用哪个实现类的方法由运行时决定
这种设计使得新增支付方式无需修改业务主逻辑,符合开闭原则。
2.3.2 接口的演进策略
从Java 8开始,接口可以有默认方法:
java复制public interface Cache {
// 传统抽象方法
Object get(String key);
// Java8默认方法
default Object getOrDefault(String key, Object defaultValue) {
Object val = get(key);
return val != null ? val : defaultValue;
}
}
这个特性让接口的演进不会破坏现有实现类,在框架升级中特别有用。
3. 设计模式与OOP实践
3.1 单例模式的正确实现
3.1.1 双重检查锁实现
我常用的线程安全单例模式:
java复制public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
关键点:volatile防止指令重排序,避免拿到未初始化完成的对象。曾经在分布式系统中因单例实现不当导致的状态不一致问题,让我深刻理解了这个细节的重要性。
3.2 工厂模式消除条件判断
3.2.1 支付工厂案例
改造前:
java复制public Payment createPayment(String type) {
if ("alipay".equals(type)) {
return new Alipay();
} else if ("wechat".equals(type)) {
return new WechatPay();
}
throw new IllegalArgumentException("不支持的支付类型");
}
使用工厂模式后:
java复制public interface PaymentFactory {
Payment create();
}
@Component
public class AlipayFactory implements PaymentFactory {
@Override
public Payment create() {
return new Alipay();
}
}
// 使用Map存储工厂实例
private Map<String, PaymentFactory> factories;
public Payment createPayment(String type) {
PaymentFactory factory = factories.get(type);
if (factory == null) {
throw new IllegalArgumentException("不支持的支付类型");
}
return factory.create();
}
这种设计让新增支付类型只需添加新工厂类,符合开闭原则。
4. 常见问题与调试技巧
4.1 对象相等性判断陷阱
4.1.1 equals与hashCode契约
我曾踩过的坑:
java复制class Person {
String id;
@Override
public boolean equals(Object o) {
// 只重写了equals没重写hashCode
}
}
// 当把Person对象放入HashSet后...
Set<Person> set = new HashSet<>();
set.add(new Person("1001"));
boolean exists = set.contains(new Person("1001")); // 可能返回false!
解决方案:
java复制@Override
public int hashCode() {
return Objects.hash(id);
}
记住:如果两个对象equals返回true,它们的hashCode必须相同!
4.2 多态中的类型转换问题
4.2.1 安全类型检查技巧
避免ClassCastException的正确姿势:
java复制if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.meow();
}
// Java16模式匹配语法更简洁
if (animal instanceof Cat cat) {
cat.meow();
}
在框架开发中,这种类型检查经常用于处理多种插件实现。
5. 性能优化与最佳实践
5.1 对象创建开销管理
5.1.1 对象池技术应用
对于创建成本高的对象(如数据库连接),我常用对象池优化:
java复制public class ConnectionPool {
private static final int MAX_SIZE = 10;
private BlockingQueue<Connection> pool = new ArrayBlockingQueue<>(MAX_SIZE);
public Connection getConnection() throws InterruptedException {
Connection conn = pool.poll();
if (conn == null && pool.size() < MAX_SIZE) {
conn = createNewConnection();
}
return conn != null ? conn : pool.take();
}
private Connection createNewConnection() {
// 实际创建逻辑
}
}
这种模式在高并发系统中可以显著降低GC压力。
5.2 不可变对象设计
5.2.1 防御性拷贝示例
在多线程环境下,我这样设计不可变类:
java复制public final class ImmutablePerson {
private final String name;
private final Date birthday;
public ImmutablePerson(String name, Date birthday) {
this.name = name;
// 防御性拷贝
this.birthday = new Date(birthday.getTime());
}
public Date getBirthday() {
// 返回拷贝而非原始引用
return new Date(birthday.getTime());
}
}
通过这种方式,即使外部修改了传入的Date对象,也不会影响ImmutablePerson的内部状态。
6. 现代Java中的OOP演进
6.1 Record类的革命性简化
Java14引入的Record类型,让简单值对象定义变得极其简洁:
java复制// 传统方式
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// 省略getters, equals, hashCode, toString...
}
// Record方式
public record Point(int x, int y) {}
在DTO定义中,Record可以大幅减少样板代码。但要注意:Record是final的,不能继承其他类。
6.2 密封类(Sealed Class)的精准控制
Java17的密封类特性,让继承体系更可控:
java复制public sealed class Shape
permits Circle, Square, Rectangle {
// 基类定义
}
public final class Circle extends Shape { /*...*/ }
public final class Square extends Shape { /*...*/ }
public non-sealed class Rectangle extends Shape { /*...*/ }
这种设计既保留了多态优势,又防止了随意继承导致的体系混乱,特别适合框架开发。
7. 从理论到实践的建议
面向对象思想需要在实际项目中才能真正掌握。我建议学习者:
- 从模仿开始:研究JDK核心类库的设计(如java.util.Collections)
- 代码重构练习:尝试用OOP原则改进自己的旧代码
- 参与开源项目:观察成熟项目中的面向对象应用
- 定期回顾基础:随着经验增长,每次重学OOP都会有新体会
我在带团队时发现,很多中级开发者容易陷入"知道概念但不会应用"的困境。解决之道就是:在真实业务场景中刻意练习OOP设计,比如尝试用策略模式替换复杂的条件判断,用装饰者模式动态添加功能等。
