Java 中 get 和 set 方法详解及实现细节

 更新时间:2025年11月11日 15:28:55   作者:祈祷苍天赐我java之术  
本文详细介绍了Java中get和set方法的使用,包括它们在面向对象编程中的作用、命名规范、实现细节、使用场景以及常见问题的解决方案,通过遵循这些最佳实践,可以提高代码的可维护性、封装性和可读性,感兴趣的朋友跟随小编一起看看吧

一、get 和 set 方法的基础认知

1.1 定义与作用

get 方法(访问器)和 set 方法(修改器)是面向对象编程中实现封装的关键技术。它们提供了一种标准化的方式来访问和修改类的私有成员变量。在 Java 等面向对象语言中,为了实现良好的封装性,通常会将类的成员变量声明为 private,然后通过 public 的 get 和 set 方法来操作这些变量。

这种设计模式具有以下特点:

  • get 方法(获取器):用于获取私有成员变量的值,通常以"get"开头
  • set 方法(设置器):用于修改私有成员变量的值,通常以"set"开头
  • 方法访问权限:通常设为 public 以保证外部可访问
  • 方法命名规范:遵循 JavaBean 规范,采用驼峰命名法

示例:一个完整的 User 类实现

public class User {
    // 私有成员变量
    private String name;
    private int age;
    private String email;
    // get方法:获取name的值
    public String getName() {
        return name;
    }
    // set方法:设置name的值
    public void setName(String name) {
        this.name = name;
    }
    // 可以添加更多getter和setter方法
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}

1.2 为什么需要 get 和 set 方法

虽然直接将成员变量声明为 public 可以简化代码编写,但这种做法会导致严重的设计问题:

  • 数据验证与控制缺失
    • 无法控制变量的赋值规则
    • 例如年龄不能为负数、邮箱必须符合格式等
  • 示例(带验证的set方法):
public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("年龄不能为负数");
    }
    this.age = age;
}
  • 内部实现变更的影响
    • 当变量的内部实现改变时(如从String改为Date)
    • 会影响所有直接访问该变量的代码
    • 通过方法访问可以保持接口稳定
  • 封装性破坏
    • 直接暴露成员变量违反面向对象设计原则
    • 使得类的内部细节对外可见
  • 额外功能无法添加
    • 无法在获取或设置时执行额外操作
    • 示例(记录访问日志):
public String getName() {
    System.out.println("访问了name属性");
    return name;
}
  • 线程安全问题
    • 无法在方法级别添加同步控制
    • 示例(线程安全的getter):
public synchronized String getName() {
    return name;
}

通过 get 和 set 方法,开发人员可以在不暴露内部实现的前提下,安全地提供变量的访问和修改通道,同时保持对数据访问的完全控制。这种模式是现代面向对象编程的最佳实践之一。

二、get 和 set 方法的命名规范

遵循规范的命名方式是写出可维护、易读代码的基础。在 Java 中,get 和 set 方法作为访问对象属性的标准方式,有着严格的命名约定。这些约定不仅被广泛认可,也是 JavaBean 规范的重要组成部分。

2.1 基本命名规则详解

get 方法命名规则

对于非布尔类型的变量:

  • 命名格式为 get + 首字母大写的变量名
  • 例如:getName()getAge()getSalary()
  • 方法签名示例:public String getName() { return name; }

对于布尔类型的变量:

  • 命名格式通常为 is + 首字母大写的变量名
  • 例如:isStudent()isActive()isAvailable()
  • 方法签名示例:public boolean isStudent() { return student; }

set 方法命名规则

适用于所有变量类型:

  • 命名格式为 set + 首字母大写的变量名
  • 例如:setName()setAge()setStudent()
  • 方法签名示例:public void setName(String name) { this.name = name; }

2.2 命名示例与应用场景

public class Person {
    // 成员变量声明
    private String name;     // 字符串类型
    private int age;         // 整型
    private boolean married; // 布尔类型
    // 正确的get/set方法命名示例
    // 非布尔类型的getter
    public String getName() { 
        return name; 
    }
    // 非布尔类型的setter
    public void setName(String name) { 
        this.name = name; 
    }
    // 非布尔类型的getter
    public int getAge() { 
        return age; 
    }
    // 非布尔类型的setter
    public void setAge(int age) { 
        this.age = age; 
    }
    // 布尔类型的getter(使用is前缀)
    public boolean isMarried() { 
        return married; 
    } 
    // 布尔类型的setter
    public void setMarried(boolean married) { 
        this.married = married; 
    }
}

实际应用中的注意事项

  1. 一致性:在整个项目中应保持命名风格一致
  2. 特殊情况处理
    • 对于缩写词(如ID),应保持首字母大写(如getID()而非getId()
    • 对于多个单词组成的变量名,每个单词首字母都应大写(如getFirstName()
  3. IDE支持:现代IDE(如IntelliJ IDEA、Eclipse)都提供自动生成getter/setter的功能,可以确保遵循规范

遵循这些命名规范不仅使代码更易读,还能确保与各种框架(如Spring、Hibernate)的良好兼容性。

三、get 和 set 方法的实现细节

3.1 参数与返回值

set 方法

  • 返回值:通常返回 void,表示该方法不返回任何值
  • 参数:参数类型必须与对应的成员变量类型完全一致
    • 例如:对于 private String name 成员变量,set 方法应为 public void setName(String name)
    • 如果成员变量是自定义对象类型,如 private User user,则 set 方法应为 public void setUser(User user)

get 方法

  • 参数:不接收任何参数
  • 返回值:返回值类型必须与对应的成员变量类型完全一致
    • 例如:对于 private int age 成员变量,get 方法应为 public int getAge()
    • 如果成员变量是集合类型,如 private List<String> items,则 get 方法应为 public List<String> getItems()

3.2 方法体中的常见操作

在实际开发中,get 和 set 方法的方法体往往不只是简单的赋值和返回,还可能包含以下高级用法:

3.2.1 参数验证

在 set 方法中可以加入业务逻辑验证,确保数据有效性:

public void setAge(int age) {
    // 验证年龄范围
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("年龄必须在0-150之间");
    }
    // 验证通过后才赋值
    this.age = age;
}

其他验证示例:

  • 验证字符串非空:if (name == null || name.trim().isEmpty())
  • 验证邮箱格式:使用正则表达式匹配
  • 验证数值范围:if (price < 0)

3.2.2 触发事件

当变量值改变时,可以触发相关业务逻辑:

private String address;
public void setAddress(String address) {
    // 保存旧值用于比较
    String oldAddress = this.address;
    this.address = address;
    // 只有地址真正改变时才触发通知
    if (!Objects.equals(oldAddress, address)) {
        notifyAddressChanged();
    }
}
private void notifyAddressChanged() {
    // 实际业务逻辑可能包括:
    // 1. 记录变更日志
    // 2. 发送MQ消息通知其他系统
    // 3. 更新相关缓存
    System.out.println("地址已更新为:" + this.address);
}

典型应用场景:

  • 用户资料变更通知
  • 订单状态变更触发业务流程
  • 配置参数修改时刷新缓存

3.2.3 延迟加载

在 get 方法中实现资源的按需初始化:

private List<String> hobbies;
public List<String> getHobbies() {
    // 第一次访问时才初始化
    if (hobbies == null) {
        hobbies = new ArrayList<>();
        // 可以添加默认值
        hobbies.add("阅读");
        hobbies.add("运动");
    }
    return Collections.unmodifiableList(hobbies); // 返回不可修改的视图
}

其他延迟加载场景:

  • 数据库连接的延迟建立
  • 大文件的按需加载
  • 复杂计算的缓存结果

注意事项:

  • 需要考虑线程安全问题
  • 对于频繁访问的属性可能会影响性能
  • 要确保延迟初始化的对象不会导致空指针异常

四、get 和 set 方法的使用场景

4.1 JavaBean 规范详解

JavaBean 规范是 Java 平台中用于创建可重用组件的标准规范,其核心要求包括:

  • 类访问权限
    • 类必须声明为 public,确保可以被其他类自由实例化和访问。例如:
public class User {
    // 类实现
}
  • 构造方法要求
    • 必须提供一个无参的公共构造方法,这是框架实例化对象的基础。例如:
public User() {} // 默认构造方法

属性访问规范

private String name;
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
  • 所有成员变量应该声明为 private,实现封装
  • 通过 public 的 getter 和 setter 方法访问属性
  • 方法命名遵循规范:getXxx()/setXxx()(布尔类型可用isXxx()) 示例:
  • 框架支持优势
  • 遵循 JavaBean 规范的类可以:
    • 被 Spring 等框架自动实例化和依赖注入
    • 支持 Hibernate 等 ORM 框架的持久化操作
    • 实现对象的深度克隆和序列化
    • 方便 IDE 的代码提示和自动补全

4.2 序列化与反序列化机制

  • JSON 序列化过程
  • 以 Jackson 为例的序列化流程:
    • 通过反射获取所有 public 方法
    • 识别 getter 方法(is/get 开头的方法)
    • 调用 getter 获取属性值
    • 将返回值转换为 JSON 字段
  • 特殊字段处理
private transient String password; // 不会被默认序列化
@JsonIgnore
public String getPassword() { // 显式排除
    return password;
}
  • 即使字段标记为 transient,只要存在 getter 仍会被序列化
  • 可使用 @JsonIgnore 注解显式排除 示例:
  • XML 序列化差异
  • JAXB 等 XML 序列化工具:
    • 依赖 @XmlElement 等注解配置
    • 默认也会通过 getter 访问属性
    • 需要无参构造方法重建对象

4.3 主流框架集成原理

Spring 框架集成

依赖注入:通过 setter 方法注入依赖对象

@Autowired
public void setService(UserService service) {
    this.service = service;
}

配置绑定:@ConfigurationProperties 通过 setter 绑定配置

MyBatis 结果映射

<resultMap id="userMap" type="User">
    <result property="name" column="user_name"/>
</resultMap>
  • 结果集自动映射时调用 setter 方法
  • 支持通过 setter 进行类型转换 示例映射:
  • JPA/Hibernate 特性
    • 延迟加载通过 getter 方法触发查询
    • 属性变更检测基于 setter 方法调用
  • 支持在 setter 中添加业务逻辑:
public void setAge(int age) {
    if(age < 0) throw new IllegalArgumentException();
    this.age = age;
}

模板引擎支持
Thymeleaf、JSP EL 表达式等视图技术都依赖 getter 方法访问属性:

<div th:text="${user.name}">...</div>

五、使用 get 和 set 方法的注意事项

5.1 不要过度使用

在面向对象编程中,并非所有的成员变量都需要提供 get 和 set 方法,过度使用会破坏封装性:

  • 只用于内部计算的临时变量,不需要对外暴露 get/set 方法
  • 例如:缓存计算结果的计算器类中的临时变量
    • 这些变量通常被标记为private且不提供任何访问方法
    • 常量(final 修饰的变量)通常只需要 get 方法,不需要 set 方法
  • 例如:数据库连接配置中的MAX_CONNECTION_SIZE
    • 常量的值在初始化后就不应被修改
    • 对于不希望被修改的变量,可以只提供 get 方法
  • 例如:用户注册时间createTime
    • 这种设计模式被称为"只读属性"

5.2 避免在 get/set 方法中执行耗时操作

get 和 set 方法应该保持简洁高效,遵循最小惊讶原则:

  • 性能影响:
    • 数据库查询或文件IO等操作不应放在get/set中
    • 在循环中调用时,如for(int i=0; i<10000; i++) obj.getValue(),性能问题会被放大
  • 可读性问题:
    • 开发者通常认为get/set是简单的属性访问
    • 复杂的内部逻辑会使代码难以理解和维护
  • 替代方案:
    • 将复杂操作拆分为独立的方法,如calculateTotal()代替getTotal()

5.3 注意封装性

  • 良好的封装是面向对象设计的重要原则:
  • 避免链式调用破坏封装:
  • 不要像这样设计:public User setName(String name) {this.name=name; return this;}
  • 这会导致set操作可以被无限链式调用,违反单一职责原则
  • 集合类型的正确处理:
private List<String> tags = new ArrayList<>();
// 危险做法:外部可以直接修改内部集合
public List<String> getTags() {
    return tags; 
}
// 安全做法1:返回防御性副本
public List<String> getTags() {
    return new ArrayList<>(tags);
}
// 安全做法2:返回不可修改视图(Java)
public List<String> getTags() {
    return Collections.unmodifiableList(tags);
}
// 安全做法3:使用不可变集合(Guava)
public ImmutableList<String> getTags() {
    return ImmutableList.copyOf(tags);
}

5.4 注意线程安全

在多线程环境下,get/set方法需要特别考虑:

  • volatile关键字:
    • 适用于基本类型的原子性操作
    • 例如:private volatile int counter;
  • synchronized关键字:
    • 方法级同步:public synchronized void setValue(int value)
    • 块级同步:synchronized(this) { /* 操作 */ }
  • 更高级的并发控制:
    • 使用Lock接口及其实现类
    • 使用原子类:AtomicInteger, AtomicReference等
    • 对于集合,可以使用ConcurrentHashMap等并发容器
  • 不可变对象:
    • 最安全的做法是设计不可变对象
    • 所有字段设为final,不提供setter方法

六、get 和 set 方法的自动化工具

手动编写 get 和 set 方法不仅繁琐,还容易出错,特别是在处理大型类时,需要为每个字段都编写对应的访问方法,既浪费时间又增加了代码维护难度。在实际开发中,我们可以利用以下工具自动生成这些方法,提高开发效率:

6.1 IDE 自带功能

主流 IDE 都提供了快速生成 getter 和 setter 的功能:

  • Eclipse:在类文件上右键→Source→Generate Getters and Setters,可以选择需要生成方法的字段
  • IntelliJ IDEA:使用快捷键 Alt+Insert→Getters and Setters,支持全选或部分选择字段生成
  • Visual Studio Code:Java 扩展也支持类似功能,可通过命令面板调用

6.2 Lombok 框架

Lombok 是一个 Java 库,通过注解自动生成 getter 和 setter 方法,极大简化代码:

import lombok.Getter;
import lombok.Setter;
// 类级别注解
@Getter @Setter
public class User {
    private String name;
    private int age;
    // 字段级注解
    @Getter(AccessLevel.PROTECTED) 
    private String password;
}

使用 Lombok 需要:

  1. 在项目中引入依赖(Maven/Gradle)
  2. 在 IDE 中安装 Lombok 插件(否则会显示编译错误)
  3. 启用注解处理(部分 IDE 需要额外配置)

Lombok 还支持生成构造器、toString()、equals()等方法,可以显著减少样板代码。

七、常见问题与解决方案

7.1 命名错误导致框架无法识别

当 getter/setter 方法命名不规范时,许多依赖反射机制的框架(如 Spring、Hibernate、Jackson 等)将无法正确识别和操作对象的属性。

常见问题表现:

  • 框架报错提示找不到属性或方法
  • 序列化/反序列化时属性丢失
  • 数据绑定失败

解决方法:

  1. 严格遵循 JavaBean 命名规范:
    • getter 方法:getXxx()(布尔属性可以用 isXxx()
    • setter 方法:setXxx(参数类型 value)
  2. 使用 IDE 自动生成方法:
    • 在 IntelliJ IDEA 中:右键 → Generate → Getter and Setter
    • 在 Eclipse 中:Source → Generate Getters and Setters
  3. 使用 Lombok 注解自动生成:
    @Getter @Setter
    private String name;
    

7.2 子类覆盖父类的 get/set 方法

  • 当子类需要覆盖父类的 getter/setter 方法时,需要特别注意:
  • 基本规则:
    • 方法签名必须匹配(方法名和参数列表)
    • 返回值类型必须兼容(相同或更具体的类型)
    • 访问修饰符不能比父类更严格
  • Java 5+ 支持协变返回类型:
public class Parent {
    public Number getValue() {
        return 0;
    }
}
public class Child extends Parent {
    @Override
    public Integer getValue() { // 合法,Integer 是 Number 的子类
        return 1;
    }
}
  • 注意事项:
    • 覆盖 setter 方法时,参数类型必须完全一致
    • 避免在覆盖的方法中改变原始语义
    • 可以使用 @Override 注解确保正确覆盖

7.3 循环依赖问题

在 getter/setter 方法中调用其他对象的方法时,容易形成循环依赖,导致以下问题:

典型场景:

class A {
    private B b;
    public B getB() {
        if(b == null) {
            b = new B();
            b.setA(this); // 循环设置
        }
        return b;
    }
}
class B {
    private A a;
    public A getA() {
        if(a == null) {
            a = new A();
            a.setB(this); // 循环设置
        }
        return a;
    }
}
  • 可能导致的问题:
    • 栈溢出(StackOverflowError)
    • 无限递归调用
    • 死锁(在多线程环境下)
    • 内存泄漏
  • 解决方案:
    • 避免在 getter/setter 中进行复杂的对象初始化
    • 使用延迟加载时要特别小心
    • 考虑使用设计模式(如工厂模式)管理对象创建
  • 对于必须的循环引用,可以:
    • 使用弱引用(WeakReference)
    • 在序列化时使用 @JsonIgnore 等注解避免循环
    • 采用 DTO 模式断开领域对象的直接关联

到此这篇关于Java 中 get 和 set 方法详解(更新版)的文章就介绍到这了,更多相关java get和set方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Windows配置多版本JDK的详细步骤

    Windows配置多版本JDK的详细步骤

    JDK是Java开发工具包的缩写,包含了Java编译器、Java虚拟机、Java类库等众多组件,是Java开发的基石,提供了编写、编译和运行Java程序所必需的工具,有时候项目需要不同的JDK版本,所以本文给大家介绍了Windows配置多版本JDK的详细步骤,需要的朋友可以参考下
    2025-04-04
  • Java HTTP协议收发MQ 消息代码实例详解

    Java HTTP协议收发MQ 消息代码实例详解

    这篇文章主要通过实例代码为大家详细介绍了如何在Java 环境下使用 HTTP 协议收发 MQ 消息,需要的朋友可以参考下
    2017-04-04
  • MybatisPlus service接口功能介绍

    MybatisPlus service接口功能介绍

    这篇文章主要介绍了MybatisPlus service接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-06-06
  • idea配置Tomcat时没有Artifacts选项的解决方法

    idea配置Tomcat时没有Artifacts选项的解决方法

    本文主要介绍了idea配置Tomcat时没有Artifacts选项的解决方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • SpringBoot+Nacos+MySQL微服务问题及解决方案

    SpringBoot+Nacos+MySQL微服务问题及解决方案

    Java微服务启动失败排查流程:检查日志、服务状态、端口监听、网络连通、配置与Nacos同步、数据库连接、系统资源及启动参数,必要时打包诊断信息并共享文档
    2025-09-09
  • Spring Boot Mybatis++ 2025详解

    Spring Boot Mybatis++ 2025详解

    文章介绍了三种基于注解SQL和查询接口的MyBatis使用方式,讨论了Entity和Example的区别,即Entity会更新所有字段,而Example仅更新非空字段,感兴趣的朋友一起看看吧
    2025-02-02
  • 一文详解Java中的动态填充Html模版并转PDF

    一文详解Java中的动态填充Html模版并转PDF

    在后端技术中,模板引擎和PDF生成工具是两个非常重要的领域,Thymeleaf和wkhtmltopdf是这两个领域的杰出代表,下面就来详细介绍一下Thymeleaf和wkhtmltopdf的技术特点吧
    2023-12-12
  • Spring Boot 整合 Neo4j的过程详解

    Spring Boot 整合 Neo4j的过程详解

    Neo4j是一个高性能的​图数据库​​,适用于存储和查询节点(Node)​​和​​关系(Relationship)​​的数据,本文介绍在springboot项目中整合neo4j,并实现基本的crud操作,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • springboot读取文件,打成jar包后访问不到的解决

    springboot读取文件,打成jar包后访问不到的解决

    这篇文章主要介绍了springboot读取文件,打成jar包后访问不到的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java代码效率优化方法(推荐)

    java代码效率优化方法(推荐)

    下面小编就为大家带来一篇java代码效率优化方法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01

最新评论