当前位置: 首页 > news >正文

Java中get()与set()方法深度解析:从封装原理到实战应用

Java中get()与set()方法深度解析:从封装原理到实战应用

引言:为什么需要get()和set()?

在Java面向对象编程中,封装(Encapsulation) 是三大核心特性之一,而get()set()方法则是实现封装的最直接手段。试想一个场景:如果类的属性直接暴露给外部(用public修饰),外部代码可以随意修改属性值(例如将一个人的年龄设为负数、将成绩设为150分),这会导致数据混乱和业务逻辑错误。

get()set()方法的出现,正是为了控制对类属性的访问权限,同时在属性的读写过程中嵌入校验逻辑,确保数据的合法性。

一、封装的底层逻辑与get/set的角色

1. 封装的核心思想

封装的本质是"隐藏内部实现,暴露安全接口"。具体来说:

  • 将类的属性用private修饰,禁止外部直接访问;
  • 提供publicget()方法(用于读取属性)和set()方法(用于修改属性);
  • get()set()中加入业务规则校验,确保数据符合预期。

这种设计的优势在于:

  • 数据安全性:避免外部代码随意篡改属性;
  • 代码可维护性:当业务规则变更时,只需修改get()/set()方法,无需改动所有调用处;
  • 逻辑一致性:所有对属性的操作都经过统一入口,确保规则执行的一致性。

2. get()与set()的基础定义规范

get()set()的命名与参数有严格规范(这也是IDE能自动生成的原因):

  • setXxx()

    • 作用:设置属性值;
    • 命名:以set开头,后接首字母大写的属性名(如属性name对应setName());
    • 参数:与属性类型一致;
    • 返回值:通常为void(也可返回当前对象实现链式调用)。
  • getXxx()

    • 作用:获取属性值;
    • 命名:以get开头,后接首字母大写的属性名(如属性age对应getAge());
    • 参数:无;
    • 返回值:与属性类型一致。
  • 布尔类型的特殊情况

    • 布尔属性(boolean)的get()方法通常命名为isXxx()(而非getXxx()),例如属性isStudent对应isStudent()

二、实战案例:从基础到进阶

1. 基础案例:学生信息管理

public class Student {// 私有属性:外部无法直接访问private String name;   // 姓名private int age;       // 年龄private double score;  // 成绩private boolean isMale; // 是否为男性// 1. name的get/setpublic String getName() {return name;}public void setName(String name) {// 校验:姓名不能为null或空字符串if (name == null || name.trim().isEmpty()) {throw new IllegalArgumentException("姓名不能为空");}this.name = name;}// 2. age的get/setpublic int getAge() {return age;}public void setAge(int age) {// 校验:年龄需在0~150之间if (age < 0 || age > 150) {throw new IllegalArgumentException("年龄必须在0~150之间");}this.age = age;}// 3. score的get/setpublic double getScore() {return score;}public void setScore(double score) {// 校验:成绩需在0~100之间if (score < 0 || score > 100) {throw new IllegalArgumentException("成绩必须在0~100之间");}this.score = score;}// 4. 布尔类型的is方法public boolean isMale() {return isMale;}public void setMale(boolean male) {isMale = male;}
}

使用示例

public class TestStudent {public static void main(String[] args) {Student stu = new Student();try {stu.setName("张三");stu.setAge(20);stu.setScore(95.5);stu.setMale(true);System.out.println("姓名:" + stu.getName());System.out.println("年龄:" + stu.getAge());System.out.println("成绩:" + stu.getScore());System.out.println("是否为男性:" + stu.isMale());} catch (IllegalArgumentException e) {System.out.println("错误:" + e.getMessage());}}
}

运行结果

姓名:张三
年龄:20
成绩:95.5
是否为男性:true

错误场景测试
若执行stu.setAge(200),会抛出异常:java.lang.IllegalArgumentException: 年龄必须在0~150之间,这正是set()方法的校验作用。

2. 进阶案例:链式调用与业务逻辑嵌入

set()方法可以返回当前对象(this),实现链式调用,使代码更简洁:

public class User {private String username;private String password;// 链式set方法:返回当前对象public User setUsername(String username) {this.username = username;return this; // 返回当前对象}public User setPassword(String password) {// 密码强度校验:至少8位,包含字母和数字if (password.length() < 8 || !password.matches(".*[a-zA-Z].*") || !password.matches(".*\\d.*")) {throw new IllegalArgumentException("密码至少8位,需包含字母和数字");}this.password = password;return this; // 返回当前对象}public String getUsername() { return username; }public String getPassword() { return password; }
}

链式调用示例

User user = new User().setUsername("zhangsan").setPassword("Zhang321"); // 链式调用,一行代码完成多个属性设置

3. 高级案例:基于get()的动态计算

get()方法不仅可以返回属性原值,还能基于其他属性动态计算结果:

public class Order {private double price; // 商品单价private int quantity; // 购买数量private double discount; // 折扣(0~1之间)// 设置单价public void setPrice(double price) {if (price < 0) throw new IllegalArgumentException("单价不能为负数");this.price = price;}// 设置数量public void setQuantity(int quantity) {if (quantity < 1) throw new IllegalArgumentException("数量至少为1");this.quantity = quantity;}// 设置折扣public void setDiscount(double discount) {if (discount < 0 || discount > 1) throw new IllegalArgumentException("折扣必须在0~1之间");this.discount = discount;}// 动态计算总价:单价×数量×折扣public double getTotalPrice() {return price * quantity * (1 - discount);}
}

使用示例

Order order = new Order();
order.setPrice(100);   // 单价100元
order.setQuantity(2);  // 购买2件
order.setDiscount(0.2); // 8折优惠
System.out.println("总价:" + order.getTotalPrice()); // 输出:160.0

三、get/set与JavaBean规范

在Java开发中,get()set()JavaBean规范的核心要求。JavaBean是一种可重用组件,本质是遵循以下规则的类:

  1. 类必须是公共的(public);
  2. 有一个无参构造方法;
  3. 属性私有化(private);
  4. 通过get()/set()方法暴露属性访问。

许多框架(如Spring、MyBatis、Jackson)依赖JavaBean规范工作:

  • Spring的依赖注入通过set()方法注入属性;
  • MyBatis将数据库查询结果通过set()方法映射到Java对象;
  • Jackson(JSON解析库)通过get()方法将对象转为JSON字段。

示例:Jackson序列化依赖get()方法

import com.fasterxml.jackson.databind.ObjectMapper;public class TestJson {public static void main(String[] args) throws Exception {Student stu = new Student();stu.setName("李四");stu.setAge(22);// Jackson会调用getXXX()方法获取属性值,转为JSONObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(stu);System.out.println(json); // 输出:{"name":"李四","age":22,"male":false}}
}

四、常见误区与最佳实践

1. 误区1:所有属性都必须生成get/set

并非所有私有属性都需要get()set()。例如:

  • 仅内部使用的临时变量(如private int tempCount)无需暴露;
  • 只读属性(如private final String id)只需get(),无需set()
  • 只写属性(如敏感的password)可只提供set()(但实际很少见)。

2. 误区2:get/set中不应该有复杂逻辑

虽然get()通常被认为是"轻操作",但合理的逻辑是必要的:

  • 允许的逻辑:数据校验、动态计算(如getTotalPrice())、缓存处理等;
  • 避免的逻辑:耗时操作(如数据库查询、网络请求),这会导致get()方法性能低下,且违背"取值"的语义。

3. 误区3:直接使用IDE生成的get/set而不校验

IDE(如IDEA、Eclipse)可以自动生成get()set(),但默认生成的方法没有校验逻辑。生产环境中,必须根据业务需求添加校验,否则封装将失去意义。

IDEA自动生成步骤

  1. 定义私有属性后,按Alt + Insert(Windows)或Cmd + N(Mac);
  2. 选择Getter and Setter,勾选需要生成的属性;
  3. 生成后手动添加校验逻辑。

4. 最佳实践

  • 命名严格遵循规范:确保框架能正确识别(如setUsername()对应username);
  • 校验逻辑集中在set():所有对属性的修改都经过校验,避免数据污染;
  • get()方法保证线程安全:若属性可能被多线程修改,get()中需考虑同步(如用volatile或锁);
  • 敏感字段处理:密码等敏感信息的get()方法需谨慎(如返回"******"而非明文)。

五、总结

get()set()方法看似简单,却是Java封装思想的具体体现,也是企业级开发中不可或缺的规范。它们的价值不仅在于控制属性访问,更在于通过统一接口保障数据的合法性和业务逻辑的一致性。

理解get()set()的设计初衷,掌握其在JavaBean、框架交互中的应用,能帮助我们写出更健壮、可维护的代码。记住:好的封装不是为了隐藏而隐藏,而是为了更安全、更高效地协作

http://www.xdnf.cn/news/1199629.html

相关文章:

  • 8. 状态模式
  • 零基础 “入坑” Java--- 十五、字符串String
  • 一场关于电商零售增长破局的深圳探索
  • 金融科技中的跨境支付、Open API、数字产品服务开发、变革管理
  • 【Ollama】大模型本地部署与 Java 项目调用指南
  • 字符串是数据结构还是数据类型?
  • 基于Prometheus+Grafana的分布式爬虫监控体系:构建企业级可观测性平台
  • Git Commit 生成与合入 Patch 指南
  • java--WebSocket简单介绍
  • 多模态视觉语言模型FILA-细粒度分辨率融合策略
  • [10月考试] B
  • Flutter 生命周期介绍
  • 基于Java的KTV点歌系统的设计与实现
  • 电商项目_核心业务_分布式ID服务
  • [STM32][HAL]stm32wbxx 超声波测距模块实现(HY-SRF05)
  • selenium完整版一览
  • 三、搭建springCloudAlibaba2021.1版本分布式微服务-springcloud loadbalancer负载均衡
  • git 提交时排除一个或多个文件
  • 【H264视频编码】一、基本概念
  • 沪深L2逐笔十档委托队列分时Tick历史数据分析处理
  • 集合框架学习
  • day25
  • vulkan从小白到专家——YUV处理
  • Windows|CUDA和cuDNN下载和安装,默认安装在C盘和不安装在C盘的两种方法
  • 《谁在翻译机器的疼痛?》——故障诊断的认知鸿沟与产教破壁之战!
  • C++ 多线程(一)
  • 低精度训练一:低精度训练介绍与大模型下载
  • 09_opencv_遍历操作图像像素
  • net8.0一键创建支持(RabbitMQ)
  • 【AI论文】WebShaper:通过信息寻求形式化实现主动式数据合成