Java面向对象编程详解
在Java编程世界中,面向对象编程(OOP)是最核心的编程范式。无论是开发企业级应用、Android应用还是大数据处理,掌握面向对象的思想都是成为优秀Java开发者的必经之路。
本文将深入浅出地讲解Java面向对象的四大特性:封装、继承、多态、抽象 ,结合Spring框架等生产级代码示例,帮助你真正理解OOP的精髓。

一、面向对象编程概述
1.1 什么是面向对象?
面向对象编程(Object-Oriented Programming,OOP)是一种将现实世界的事物抽象为程序中"对象"的编程思想。
核心理念:
- 万物皆对象:现实世界的任何事物都可以抽象为对象
- 对象有状态和行为:状态用属性表示,行为用方法表示
- 对象之间通过消息通信:方法调用就是发送消息
1.2 面向对象 vs 面向过程
| 对比项 | 面向过程 | 面向对象 |
|---|---|---|
| 关注点 | 解决问题的步骤 | 解决问题的对象 |
| 代码组织 | 函数 | 类和对象 |
| 数据安全 | 数据暴露 | 数据封装 |
| 代码复用 | 函数复用 | 继承、组合 |
| 扩展性 | 较差 | 良好 |
| 适用场景 | 简单脚本 | 复杂系统 |

二、封装:保护数据的第一道防线
2.1 什么是封装?
封装(Encapsulation) 是将对象的属性和方法包装在一起,隐藏内部实现细节,只对外暴露必要的接口。
封装的三要素:
- 私有化属性:使用private修饰
- 提供公共访问方法:getter和setter
- 在方法中加入控制逻辑:数据验证
2.2 封装的实际应用
java
/**
* 用户实体类 - 演示封装
* 实际生产中的写法
*/
public class User {
// 私有属性
private Long id;
private String username;
private String password;
private String email;
private Integer age;
private LocalDateTime createTime;
// 无参构造器
public User() {
this.createTime = LocalDateTime.now();
}
// 全参构造器
public User(String username, String password, String email) {
this();
this.username = username;
setPassword(password); // 使用setter进行加密
setEmail(email); // 使用setter进行校验
}
// Getter方法
public Long getId() {
return id;
}
public String getUsername() {
return username;
}
// 密码不直接返回,返回脱敏后的
public String getPassword() {
return "******";
}
// Setter方法 - 包含业务逻辑
public void setUsername(String username) {
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
if (username.length() < 3 || username.length() > 20) {
throw new IllegalArgumentException("用户名长度必须在3-20之间");
}
this.username = username.trim();
}
// 密码加密存储
public void setPassword(String password) {
if (password == null || password.length() < 6) {
throw new IllegalArgumentException("密码长度不能小于6位");
}
// 实际生产中使用BCrypt加密
this.password = hashPassword(password);
}
// 邮箱格式验证
public void setEmail(String email) {
if (email != null && !email.matches("^[\\w-\\.]+@[\\w-]+\\.[a-z]{2,}$")) {
throw new IllegalArgumentException("邮箱格式不正确");
}
this.email = email;
}
// 年龄范围验证
public void setAge(Integer age) {
if (age != null && (age < 0 || age > 150)) {
throw new IllegalArgumentException("年龄必须在0-150之间");
}
this.age = age;
}
// 私有方法 - 密码哈希
private String hashPassword(String password) {
// 简化示例,实际使用BCrypt
return "HASHED_" + password.hashCode();
}
}
2.3 Spring框架中的封装实践
Spring框架大量使用封装来保护核心组件:
java
/**
* 模拟Spring的BeanFactory封装思想
*/
public class SimpleBeanFactory {
// 私有的Bean容器
private final Map<String, Object> beanMap = new ConcurrentHashMap<>();
// 私有的Bean定义
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
// 对外暴露的获取Bean方法
public Object getBean(String beanName) {
// 先从缓存获取
Object bean = beanMap.get(beanName);
if (bean != null) {
return bean;
}
// 创建Bean(简化版)
BeanDefinition definition = beanDefinitionMap.get(beanName);
if (definition == null) {
throw new RuntimeException("Bean not found: " + beanName);
}
bean = createBean(definition);
beanMap.put(beanName, bean);
return bean;
}
// 私有的创建Bean方法
private Object createBean(BeanDefinition definition) {
// 内部实现细节对外隐藏
try {
return definition.getBeanClass().newInstance();
} catch (Exception e) {
throw new RuntimeException("创建Bean失败", e);
}
}
}

三、继承:代码复用的利器
3.1 什么是继承?
继承(Inheritance) 是子类获得父类的属性和方法的机制,是实现代码复用的重要手段。
继承的特点:
- Java只支持单继承(一个类只能有一个父类)
- 支持多层继承(A继承B,B继承C)
- 所有类都隐式继承Object类
- 使用extends关键字
3.2 继承的实际应用
java
/**
* 基础实体类 - 所有实体的父类
* 生产级代码通常都有这样的基类
*/
public abstract class BaseEntity {
protected Long id;
protected LocalDateTime createTime;
protected LocalDateTime updateTime;
protected String createBy;
protected String updateBy;
protected Boolean deleted = false;
// 创建时自动填充
public void onCreate() {
this.createTime = LocalDateTime.now();
this.updateTime = this.createTime;
}
// 更新时自动填充
public void onUpdate() {
this.updateTime = LocalDateTime.now();
}
// Getter和Setter省略...
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
}
/**
* 用户实体 - 继承基础实体
*/
public class UserEntity extends BaseEntity {
private String username;
private String password;
private String email;
private Integer status;
// 子类特有的方法
public boolean isActive() {
return status != null && status == 1;
}
// Getter和Setter...
}
/**
* 订单实体 - 继承基础实体
*/
public class OrderEntity extends BaseEntity {
private String orderNo;
private Long userId;
private BigDecimal totalAmount;
private Integer status;
// 子类特有的方法
public boolean canCancel() {
return status != null && status == 0; // 待支付状态可取消
}
}
3.3 MyBatis-Plus中的继承应用
java
/**
* 通用Service接口 - MyBatis-Plus风格
*/
public interface IBaseService<T> {
T getById(Long id);
List<T> list();
boolean save(T entity);
boolean updateById(T entity);
boolean removeById(Long id);
}
/**
* 通用Service实现
*/
public abstract class BaseServiceImpl<M extends BaseMapper<T>, T>
implements IBaseService<T> {
@Autowired
protected M baseMapper;
@Override
public T getById(Long id) {
return baseMapper.selectById(id);
}
@Override
public List<T> list() {
return baseMapper.selectList(null);
}
@Override
public boolean save(T entity) {
return baseMapper.insert(entity) > 0;
}
@Override
public boolean updateById(T entity) {
return baseMapper.updateById(entity) > 0;
}
@Override
public boolean removeById(Long id) {
return baseMapper.deleteById(id) > 0;
}
}
/**
* 用户Service - 继承通用实现
*/
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserEntity>
implements IUserService {
// 只需要实现特有的业务方法
public UserEntity findByUsername(String username) {
return baseMapper.selectByUsername(username);
}
}

四、多态:灵活性的源泉
4.1 什么是多态?
多态(Polymorphism) 是指同一个行为具有多种不同表现形式的能力。
多态的三个必要条件:
- 继承或实现接口
- 方法重写
- 父类引用指向子类对象
4.2 多态的实际应用
java
/**
* 支付接口 - 定义支付行为
*/
public interface PaymentService {
/**
* 执行支付
* @param orderId 订单ID
* @param amount 支付金额
* @return 支付结果
*/
PaymentResult pay(String orderId, BigDecimal amount);
/**
* 查询支付状态
*/
PaymentStatus queryStatus(String orderId);
/**
* 获取支付方式名称
*/
String getPaymentType();
}
/**
* 支付宝支付实现
*/
@Service("alipayService")
public class AlipayServiceImpl implements PaymentService {
@Override
public PaymentResult pay(String orderId, BigDecimal amount) {
System.out.println("调用支付宝SDK进行支付...");
// 调用支付宝API
// AlipayClient.execute(request);
return PaymentResult.success("支付宝支付成功");
}
@Override
public PaymentStatus queryStatus(String orderId) {
System.out.println("查询支付宝订单状态...");
return PaymentStatus.SUCCESS;
}
@Override
public String getPaymentType() {
return "ALIPAY";
}
}
/**
* 微信支付实现
*/
@Service("wechatPayService")
public class WechatPayServiceImpl implements PaymentService {
@Override
public PaymentResult pay(String orderId, BigDecimal amount) {
System.out.println("调用微信支付SDK...");
// 调用微信支付API
return PaymentResult.success("微信支付成功");
}
@Override
public PaymentStatus queryStatus(String orderId) {
System.out.println("查询微信支付订单状态...");
return PaymentStatus.SUCCESS;
}
@Override
public String getPaymentType() {
return "WECHAT";
}
}
/**
* 银联支付实现
*/
@Service("unionPayService")
public class UnionPayServiceImpl implements PaymentService {
@Override
public PaymentResult pay(String orderId, BigDecimal amount) {
System.out.println("调用银联支付接口...");
return PaymentResult.success("银联支付成功");
}
@Override
public PaymentStatus queryStatus(String orderId) {
return PaymentStatus.SUCCESS;
}
@Override
public String getPaymentType() {
return "UNION_PAY";
}
}
4.3 策略模式 + 多态的生产实践
java
/**
* 支付策略上下文 - 利用多态实现策略模式
*/
@Component
public class PaymentContext {
private final Map<String, PaymentService> paymentServiceMap;
// Spring自动注入所有PaymentService实现
@Autowired
public PaymentContext(List<PaymentService> paymentServices) {
paymentServiceMap = paymentServices.stream()
.collect(Collectors.toMap(
PaymentService::getPaymentType,
Function.identity()
));
}
/**
* 执行支付 - 多态的典型应用
*/
public PaymentResult executePayment(String payType, String orderId,
BigDecimal amount) {
// 根据支付类型获取对应的实现
PaymentService paymentService = paymentServiceMap.get(payType);
if (paymentService == null) {
throw new IllegalArgumentException("不支持的支付方式: " + payType);
}
// 多态调用 - 同一个方法,不同的实现
return paymentService.pay(orderId, amount);
}
}
/**
* 订单服务 - 使用支付上下文
*/
@Service
public class OrderService {
@Autowired
private PaymentContext paymentContext;
public void processPayment(Order order) {
// 根据用户选择的支付方式,调用不同的支付实现
PaymentResult result = paymentContext.executePayment(
order.getPayType(),
order.getOrderNo(),
order.getAmount()
);
if (result.isSuccess()) {
order.setStatus(OrderStatus.PAID);
}
}
}

五、抽象:设计的艺术
5.1 什么是抽象?
抽象(Abstraction) 是将对象的共同特征提取出来,形成类或接口的过程。
Java中的抽象方式:
- 抽象类(abstract class):可以有抽象方法和具体方法
- 接口(interface):Java 8后可以有默认方法
5.2 抽象类的应用
java
/**
* 抽象模板 - 数据导出器
* 使用模板方法模式
*/
public abstract class AbstractDataExporter<T> {
/**
* 导出数据 - 模板方法(final防止子类修改流程)
*/
public final void export(List<T> dataList, String filePath) {
// 1. 数据校验
validateData(dataList);
// 2. 数据预处理
List<T> processedData = preProcess(dataList);
// 3. 执行导出(抽象方法,子类实现)
doExport(processedData, filePath);
// 4. 后置处理
postProcess(filePath);
System.out.println("导出完成: " + filePath);
}
// 钩子方法 - 子类可选重写
protected void validateData(List<T> dataList) {
if (dataList == null || dataList.isEmpty()) {
throw new IllegalArgumentException("导出数据不能为空");
}
}
// 钩子方法 - 默认不处理
protected List<T> preProcess(List<T> dataList) {
return dataList;
}
// 抽象方法 - 子类必须实现
protected abstract void doExport(List<T> dataList, String filePath);
// 钩子方法 - 默认不处理
protected void postProcess(String filePath) {
// 子类可重写
}
}
/**
* Excel导出器
*/
@Component
public class ExcelExporter extends AbstractDataExporter<Map<String, Object>> {
@Override
protected void doExport(List<Map<String, Object>> dataList, String filePath) {
System.out.println("使用POI导出Excel文件...");
// 实际使用Apache POI或EasyExcel
}
@Override
protected void postProcess(String filePath) {
System.out.println("Excel导出后处理:添加水印");
}
}
/**
* CSV导出器
*/
@Component
public class CsvExporter extends AbstractDataExporter<Map<String, Object>> {
@Override
protected void doExport(List<Map<String, Object>> dataList, String filePath) {
System.out.println("导出CSV文件...");
// 使用OpenCSV或手动拼接
}
}
/**
* PDF导出器
*/
@Component
public class PdfExporter extends AbstractDataExporter<Map<String, Object>> {
@Override
protected List<Map<String, Object>> preProcess(List<Map<String, Object>> dataList) {
System.out.println("PDF预处理:格式化数据");
return dataList;
}
@Override
protected void doExport(List<Map<String, Object>> dataList, String filePath) {
System.out.println("使用iText导出PDF文件...");
}
}
5.3 接口的应用
java
/**
* 缓存接口 - 定义缓存行为
*/
public interface CacheService {
void set(String key, Object value);
void set(String key, Object value, long timeout, TimeUnit unit);
<T> T get(String key, Class<T> clazz);
boolean delete(String key);
boolean hasKey(String key);
// Java 8 默认方法
default void setWithDefaultExpire(String key, Object value) {
set(key, value, 30, TimeUnit.MINUTES);
}
}
/**
* Redis缓存实现
*/
@Service
@Primary
public class RedisCacheService implements CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
@Override
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
@Override
public <T> T get(String key, Class<T> clazz) {
Object value = redisTemplate.opsForValue().get(key);
return clazz.cast(value);
}
@Override
public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
@Override
public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
}
/**
* 本地缓存实现(用于开发环境)
*/
@Service
public class LocalCacheService implements CacheService {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
@Override
public void set(String key, Object value) {
cache.put(key, value);
}
@Override
public void set(String key, Object value, long timeout, TimeUnit unit) {
cache.put(key, value);
// 简化版,实际需要处理过期
}
@Override
public <T> T get(String key, Class<T> clazz) {
return clazz.cast(cache.get(key));
}
@Override
public boolean delete(String key) {
return cache.remove(key) != null;
}
@Override
public boolean hasKey(String key) {
return cache.containsKey(key);
}
}

六、面向对象设计原则
6.1 SOLID原则
| 原则 | 说明 | 示例 |
|---|---|---|
| S - 单一职责 | 一个类只负责一件事 | UserService只处理用户业务 |
| O - 开闭原则 | 对扩展开放,对修改关闭 | 通过接口添加新支付方式 |
| L - 里氏替换 | 子类可以替换父类 | List list = new ArrayList() |
| I - 接口隔离 | 接口要小而专一 | 拆分大接口为多个小接口 |
| D - 依赖倒置 | 依赖抽象而非具体 | 依赖PaymentService接口 |
6.2 组合优于继承
java
/**
* 使用组合而非继承
*/
public class OrderService {
// 组合:持有其他对象的引用
private final UserService userService;
private final PaymentService paymentService;
private final InventoryService inventoryService;
private final NotificationService notificationService;
public OrderService(UserService userService,
PaymentService paymentService,
InventoryService inventoryService,
NotificationService notificationService) {
this.userService = userService;
this.paymentService = paymentService;
this.inventoryService = inventoryService;
this.notificationService = notificationService;
}
public Order createOrder(OrderRequest request) {
// 1. 校验用户
User user = userService.getById(request.getUserId());
// 2. 校验库存
inventoryService.checkStock(request.getItems());
// 3. 创建订单
Order order = buildOrder(request, user);
// 4. 扣减库存
inventoryService.deductStock(request.getItems());
// 5. 发送通知
notificationService.sendOrderCreatedNotification(order);
return order;
}
}

七、总结
核心要点
- 封装:保护数据,隐藏实现,对外提供接口
- 继承:代码复用,建立类层次结构
- 多态:同一接口,不同实现,提高灵活性
- 抽象:提取共性,定义规范,降低耦合
实践建议
- 优先使用组合而非继承
- 面向接口编程
- 遵循SOLID原则
- 保持类的职责单一
- 合理使用设计模式
