Java面向对象编程详解

Java面向对象编程详解

在Java编程世界中,面向对象编程(OOP)是最核心的编程范式。无论是开发企业级应用、Android应用还是大数据处理,掌握面向对象的思想都是成为优秀Java开发者的必经之路。

本文将深入浅出地讲解Java面向对象的四大特性:封装、继承、多态、抽象 ,结合Spring框架等生产级代码示例,帮助你真正理解OOP的精髓。


一、面向对象编程概述

1.1 什么是面向对象?

面向对象编程(Object-Oriented Programming,OOP)是一种将现实世界的事物抽象为程序中"对象"的编程思想。

核心理念

  • 万物皆对象:现实世界的任何事物都可以抽象为对象
  • 对象有状态和行为:状态用属性表示,行为用方法表示
  • 对象之间通过消息通信:方法调用就是发送消息

1.2 面向对象 vs 面向过程

对比项 面向过程 面向对象
关注点 解决问题的步骤 解决问题的对象
代码组织 函数 类和对象
数据安全 数据暴露 数据封装
代码复用 函数复用 继承、组合
扩展性 较差 良好
适用场景 简单脚本 复杂系统

二、封装:保护数据的第一道防线

2.1 什么是封装?

封装(Encapsulation) 是将对象的属性和方法包装在一起,隐藏内部实现细节,只对外暴露必要的接口。

封装的三要素

  1. 私有化属性:使用private修饰
  2. 提供公共访问方法:getter和setter
  3. 在方法中加入控制逻辑:数据验证

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) 是指同一个行为具有多种不同表现形式的能力。

多态的三个必要条件

  1. 继承或实现接口
  2. 方法重写
  3. 父类引用指向子类对象

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;
    }
}

七、总结

核心要点

  1. 封装:保护数据,隐藏实现,对外提供接口
  2. 继承:代码复用,建立类层次结构
  3. 多态:同一接口,不同实现,提高灵活性
  4. 抽象:提取共性,定义规范,降低耦合

实践建议

  • 优先使用组合而非继承
  • 面向接口编程
  • 遵循SOLID原则
  • 保持类的职责单一
  • 合理使用设计模式

相关推荐
zhangyifang_0092 小时前
Spring中的BeanFactory类
java·后端·spring
大学生资源网2 小时前
java毕业设计之面向校园的助力跑腿系统设计与实现源码(源码+文档+数据库)
java·数据库·mysql·毕业设计·源码·springboot
quikai19813 小时前
python练习第六组
java·前端·python
222you3 小时前
线程的常用方法
java·开发语言
云栖梦泽3 小时前
易语言界面美化与组件扩展
开发语言
catchadmin3 小时前
PHP 值对象实战指南:避免原始类型偏执
android·开发语言·php
Trouville013 小时前
Python中encode和decode的用法详解
开发语言·python
是梦终空3 小时前
JAVA毕业设计259—基于Java+Springboot+vue3工单管理系统的设计与实现(源代码+数据库+开题报告)
java·spring boot·vue·毕业设计·课程设计·工单管理系统·源代码
JS_GGbond3 小时前
JavaScript事件循环:餐厅里的“宏任务”与“微任务”
开发语言·javascript·ecmascript