进一步理解get和set

做CRUD的功能时,我们常常会定义一个和表对应的实体类信息,然后这个实体类信息的属性和表中的字段一一对应,然后加上每个属性的get和set方法;更规范的做法是,在此基础上再加一个DTO类,它与实体类

长得几乎一样,但是这个类不直接和表关联。

 

之前一直不明白为何要再定义一个dto类,也觉得get和set方法不外乎是:

public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		
		this.email = email;
	}

 这种“千篇一律”的写法。。直到最近做了对字段加解密的活,才被虐得很惨。。

 

下面就以对email字段来加解密,说一说我的收获。

假设有一个和表对应的实体类Info(Hibernate):

@SuppressWarnings("serial")
@Table(name = "INFO")
@Entity
public class Info extends BasicEntity {
	@Column(name = "EMAIL")
	private String email;
	
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		
		this.email = email;
	}
}

 还有一个对应的DTO:

public class InfoDTO  {
	
	private String email;
	
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		
		this.email = email;
	}
}

 现在如果要对email字段加解密,就是在数据库里看到的是密文,在前端UI看到的是明文。此时就跟get和set有关了。。

我们在此不讨论如何加解密。一般而言,Entity的set方法用于保存入库,get方法用于从库里取数据,你会很正常的想到这样:

@SuppressWarnings("serial")
@Table(name = "INFO")
@Entity
public class Info extends BasicEntity {
	@Column(name = "EMAIL")
	private String email;
	
	public String getEmail() {
		email = ....(emial);//解密的伪代码
		return email;
	}

	public void setEmail(String email) {
		email = ....(emial);//加密的伪代码
		this.email = email;
	}
}

 set方法没有问题,但是get方法就是一个“陷阱”!在首次解密数据库里的密文email时,确实能在前端正常显示明文,但是同时数据库里的email字段也会变成明文!我们在第二次以后再去访问时,因为已经是

明文,再解密的话就会报错!

所以get方法也可能改变数据库里的值,因为一旦你在get方法里对该字段做了逻辑处理后,email是全局变量,会直接影响数据库里面的值!一般我们只认为set会改变库里的值,而get不会。但是要看get方法里

有没有对变量做逻辑处理,这就颠覆了"固化"的思维。

此时DTO类就派上用场啦!可以这样改造,保持Entity实体类的get方法不变,DTO类的get方法再做解密!如:

@SuppressWarnings("serial")
@Table(name = "INFO")
@Entity
public class Info extends BasicEntity {
	@Column(name = "EMAIL")
	private String email;
	
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		email = ....(emial);//加密的伪代码
		this.email = email;
	}
}

 DTO类:

public class InfoDTO  {
	
	private String email;
	
	public String getEmail() {
		email = ....(emial);//解密的伪代码
		return email;
	}

	public void setEmail(String email) {
		
		this.email = email;
	}
}

 这样,无论你访问多少次。数据库里的密文会一直保持,我们可以通过debug知道代码的执行顺序是:

Entity类的get方法从数据库里取出密文->DTO类的set方法把Entity类get到的值赋给自己->DTO类的get方法把自己get到的值做处理(直接显示或做处理)

 

从这个角度,可以将DTO类理解成一个数据的备份,不直接与数据库挂钩,也就不会影响数据库里的值

 

还有一种情景是UI输入查询/添加或修改去保存,这是一个与上面方向相反的过程。

此时DTO类可以用于收集form查询或添加/修改表单的数据,其实也可以用Map,看字段值的多少了。

同样,如果我们考虑email这个字段,用户输入的肯定是明文,存到数据库里需是密文,此时因为在Entity类里set方法直接是加密的了,所以我们要保持在DTO里get到的值是明文,执行顺序:

用户输入明文->DTO类的set方法来保存输入信息->DTO类的get方法来获得输入->Entity类的set方法加密

 

这时候我们会发现,如果在DTO类的get方法里还保留解密逻辑,就会出错,所以此时DTO的get方法又不能加了。

 

这就引申出一个问题,我们一般DTO当作Entity类和UI之间的介质,当他要作为接收参数的角色时,get方法里也不能加逻辑处理,此时需要注意!此时,我们只能用其他参数接收载体如Map

所以当字段需要做逻辑处理,不再是传统的get和set时,需要注意get和set对值的改变!

 

下面一张图是我对get和set的理解(图是用wps画的,很渣勿喷~)



 以上加解密只是一个例子,用于说明字段不再是单纯get和set时需要注意的地方!!!

<think>好的,用户想了解如何在Java中定义使用gettersetter方法。首先,我需要回忆相关的知识点,确保回答准确。根据系统提供的引用资料,GetterSetter用于访问修改对象的属性,这是面向对象编程的基本概念。 首先,定义部分。Getter方法用于获取属性值,通常以get开头加属性名,如getName()。Setter方法用于设置属性值,以set开头,如setName(String name)。需要提到命名规范,遵循驼峰式,返回类型参数的正确使用。 然后,需要说明为什么需要这些方法。主要是为了封装,保护数据不被直接访问,通过方法来控制访问修改,比如可以在setter中加入验证逻辑。例如,年龄不能为负数,可以在setAge方法里检查。 接下来是具体如何定义。要给出一个示例类,比如Student类,有nameage属性,将它们设为private。然后分别为每个属性编写getset方法。代码示例要正确,符合Java语法,并且展示如何在setter中加入验证。 然后,使用部分。要说明在main方法中如何创建对象,调用setter设置值,用getter获取值。这部分需要代码示例,显示正确的调用方式,比如student.setName("张三"),然后System.out.println(student.getName())。 可能还需要提到继承的情况,比如B类继承A类,如何覆盖或使用父类的gettersetter。但根据用户的问题,可能不需要太深入,但可以简要提及,引用资料中的引用[4]提到了B类继承A类的情况,可以引用说明。 另外,常见的错误需要注意,比如直接暴露属性,或者方法命名不规范,返回类型错误等。引用资料中的引用[3]提到了常见的错误,需要指出这些,帮助用户避免。 最后,生成相关问题,比如为什么要用getter/setter,如何验证数据,是否可以省略,以及继承中的注意事项。这些问题要围绕用户可能进一步想了解的点展开。 检查LaTeX格式是否按照要求,行内公式用$...$,独立公式用$$...$$,但这里可能用不到数学公式,所以不需要。确保回答结构清晰,分点说明,代码示例正确,引用正确标注。例如,在提到封装数据验证时,引用[1][3]。 现在组织语言,确保步骤清晰,用户能一步步理解如何定义使用,以及背后的原理。可能还需要对比直接访问属性通过方法的区别,强调封装的好处。</think>### Java中gettersetter方法的定义与使用 #### 一、基本定义 1. **Getter方法** 用于获取对象的私有属性值,命名格式为`get`+属性名(首字母大写),例如属性`name`对应的方法为`getName()`[^1][^3]。 ```java public String getName() { return this.name; } ``` 2. **Setter方法** 用于设置对象的私有属性值,命名格式为`set`+属性名(首字母大写),例如`setName(String name)`[^1]。 ```java public void setName(String name) { this.name = name; } ``` #### 二、实现步骤 1. **属性私有化** 将类的成员变量声明为`private`,禁止外部直接访问: ```java public class Student { private String name; private int age; } ``` 2. **生成getter/setter方法** 手动或通过IDE自动生成方法,例如: ```java // Getter public int getAge() { return this.age; } // Setter(含数据验证) public void setAge(int age) { if (age >= 0) { // 数据合法性校验 this.age = age; } else { throw new IllegalArgumentException("年龄不能为负数"); } } ``` #### 三、使用方法 1. **设置属性值** 通过`setXxx()`方法赋值: ```java Student student = new Student(); student.setName("张三"); student.setAge(20); ``` 2. **获取属性值** 通过`getXxx()`方法读取: ```java System.out.println(student.getName()); // 输出:张三 System.out.println(student.getAge()); // 输出:20 ``` #### 四、核心作用 1. **数据封装** 隐藏属性实现细节,避免外部直接修改数据[^3]。 2. **数据验证** 在`setter`中可添加业务逻辑(如范围检查、格式校验)。 3. **扩展性** 后续修改属性类型时,可保持方法接口不变[^2]。 #### 五、继承中的使用 子类可通过`@Override`重写父类的`getter/setter`方法,例如: ```java public class GraduateStudent extends Student { @Override public void setAge(int age) { // 可添加针对研究生的特殊校验 super.setAge(age); } } ``` (引用自继承场景示例[^4])
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值