什么是Getter、Setter

package Bean;public class SimpleGetterAndSetter {private int number;public int getNumber() {return number;}public void setNumber(int number) {this.number = number;}
}

因为number变量是私有的,所以外部类不能直接访问到这个变量
相反,外部代码必须调用getter getNumber()和setter setNumber()才能读取或更新变量

因此,setter是一种更新变量值的方法。Getter是一种读取变量值的方法。
Getter和setter在Java中也称为访问器和更改器。

为什么要使用getter和setter?

通过使用getter和setter,程序员可以控制如何以正确的方式访问和更新他的重要变量,例如在指定范围内更改变量的值。 考虑以下setter方法的代码:

    public void setNumber(int number) {//如果设置的参数不满足条件就抛出异常if (number < 10 || number > 100) {throw new IllegalArgumentException();}this.number = number;}

假设可以直接更新变量number,则调用者可以为其设置任意值!
使用getter setter可以对变量的读取和设置做出控制,假如直接访问变量,无法对读取和设置做出限制

getter和setter的命名约定(略)

实现getter和setter时的常见错误

错误1:没有使用受限的访问修饰符

变量firstName声明为public,因此可以直接使用点(.)运算符对其进行访问,从而使setter和getter无效。 这种情况的解决方法是使用更多受限制的访问修饰符,例如protectedprivate

错误2:直接在setter中分配对象引用
一旦在封装器之外修改了对象引用就会破坏封装

package Bean;public class SimpleGetterAndSetter {private int[] scores;//    将变量直接赋值给对象引用public void setScores(int[] scores) {this.scores = scores;}public void displayScores() {for (int i = 0; i < this.scores.length; i++) {System.out.println(this.scores[i] + " ");}System.out.println("");}public static void main(String[] args) {SimpleGetterAndSetter simpleGetterAndSetter = new SimpleGetterAndSetter();int[] myScores = {5, 5, 4, 3, 2, 4};simpleGetterAndSetter.setScores(myScores);simpleGetterAndSetter.displayScores();myScores[1] = 1;simpleGetterAndSetter.displayScores();}
}

通过第4行myScores[1] = 1;的分配,您可以意识到2nd元素的值从5更改为1。这有什么关系? 好吧,这意味着可以在设置器方法的范围之外修改数据,这会破坏设置器的封装目的。 为什么会这样呢? 让我们再次看一下上面的setScores()方法,可以发现在setter方法 中修改的对象就是当前对象的数据,所以通过修改传递的参数就修改了对象的数据,破坏了封装的目的

setScores方法中,成员变量scores直接分配给方法的参数变量scores。 这意味着两个变量都引用内存中的同一对象-myScores数组对象,因此,对实参和形参进行的更改实际上是在同一对象上进行的。所以一旦修改了传递进的参数的值,就等于修改了Setter方法中设置的值,破坏了封装

在Setter中将新对象赋值给当前对象加强封装

package Bean;public class SimpleGetterAndSetter {private int[] scores;//    将变量直接赋值给对象引用
//    public void setScores(int[] scores) {//        this.scores = scores;
//    }public void setScores(int[] scores) {//       创建一个新的数组对象this.scores = new int[scores.length];
//       把数组参数的值逐个的复制到新创建的数组中去,这样,两个数组就相互独立,互不影响System.arraycopy(scores, 0, this.scores, 0, scores.length);}public void displayScores() {for (int i = 0; i < this.scores.length; i++) {System.out.println(this.scores[i] + " ");}System.out.println("");}public static void main(String[] args) {SimpleGetterAndSetter simpleGetterAndSetter = new SimpleGetterAndSetter();int[] myScores = {5, 5, 4, 3, 2, 4};simpleGetterAndSetter.setScores(myScores);simpleGetterAndSetter.displayScores();myScores[1] = 1;simpleGetterAndSetter.displayScores();}
}

Attention!!!So, the rule of thumb is, if you pass an object reference into a setter method, then don’t copy that reference into the internal variable directly. Instead, you should find some ways to copy values of the passed object into the internal object, like we have copied elements from one array to another using System.arraycopy() method.

错误3:直接在getter中返回对象引用

package Bean;public class SimpleGetterAndSetter {private int[] scores;//    将变量直接赋值给对象引用
//    public void setScores(int[] scores) {//        this.scores = scores;
//    }public void setScores(int[] scores) {//       创建一个新的数组对象this.scores = new int[scores.length];
//       把数组参数的值逐个的复制到新创建的数组中去,这样,两个数组就相互独立,互不影响System.arraycopy(scores, 0, this.scores, 0, scores.length);}public void displayScores() {for (int i = 0; i < this.scores.length; i++) {System.out.println(this.scores[i] + " ");}System.out.println("");}public int[] getScores() {return this.scores;}public static void main(String[] args) {SimpleGetterAndSetter simpleGetterAndSetter = new SimpleGetterAndSetter();int[] myScores = {5, 5, 4, 3, 2, 4};
//       传递参数数据simpleGetterAndSetter.setScores(myScores);//        查看传递的数据simpleGetterAndSetter.displayScores();//        通过getter方法获取数据 直接返回对象引用int[] copyScore = simpleGetterAndSetter.getScores();//        更改获取到的对象引用数据copyScore[1] = 1;
//        重新展示数据,再次展示的数据与第一次传递的数据出现变化,直接返回对象引用破坏了封装simpleGetterAndSetter.displayScores();}
}

在访问器中返回对象的副本加强封装

    public int[] getScores() {int[] copy = new int[this.scores.length];System.arraycopy(this.scores, 0, copy, 0, copy.length);return copy;}

为原始类型实现getter和setter方法

使用基元类型(int,float,double,boolean,char…),您可以直接在setter / getter中自由分配/返回值,因为Java将一个基元的值复制到了另一个而不是复制对象引用。 因此,可以避免直接返回对象引用和直接赋值对象引用所导致的错误。
例如,以下代码是安全的,因为setter和getter涉及到的是float的原始类型:

    private float amount;public void setAmount() {this.amount = amount;}public float getAmount() {return this.amount;}

实现常见对象类型的getter和setter方法

字符串对象的获取器和设置器
String是一种对象类型,但是它是不可变的,这意味着一旦创建了String对象,就不能更改其String文字。 换句话说,对该String对象的每次更改都会导致创建一个新的String对象。 因此,像原始类型一样,您可以安全地为String变量实现getter和setter,如下所示:

    private String address;public void setAddress(String address) {this.address = address;}public String getAddress() {return this.address;}

日期对象的获取器和设置器
The java.util.Date class implements clone() method from the Object class. The method clone() returns a copy of the object, so we can use it for the getter and setter, like the following example:

    private Date birthdate;public void setBirthdate(Date birthdate) {this.birthdate = (Date) birthdate.clone();}public Date getBirthdate() {return (Date) this.birthdate.clone();}

实现集合类型的getter和setter

String集合封装的错误示范

package Bean;import java.util.ArrayList;
import java.util.List;public class SimpleGetterAndSetter {private List<String> listTitles;public void setListTitles(List<String> titles) {this.listTitles = titles;}public List<String> getListTitles() {return this.listTitles;}public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Name");list.add("Address");list.add("Email");list.add("Job");SimpleGetterAndSetter simpleGetterAndSetter = new SimpleGetterAndSetter();simpleGetterAndSetter.setListTitles(list);System.out.println("Titles 1:" + list);list.set(2, "Habilitation");List<String> list1 = simpleGetterAndSetter.getListTitles();System.out.println("Titles 2:" + list1);list1.set(0, "Full name");List<String> list2 = simpleGetterAndSetter.getListTitles();System.out.println("Titles 3:" + list2);}
}

That means the collection can be modified from code outside of the getter and setter.
For a collection of Strings, one solution is to use the constructor that takes another collection as argument, for example we can change code of the above getter and setter as follows:

String集合的正确封装

    private List<String> listTitles;public void setListTitles(List<String> titles) {//        this.listTitles = titles;this.listTitles = new ArrayList<String>(titles);}public List<String> getListTitles() {//        return this.listTitles;return new ArrayList<String>(this.listTitles);}

NOTE: The constructor approach above is only working with collections of Strings, but it will not work for collections objects. Consider the following example for a collection of Person object:

对象集合类型封装的错误示范
使用封装String集合的方式封装对象集合没有用,因为String集合中的String是不变对象,如果是对象集合就不能使用String集合的封装方式

package Bean;import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;public class CollectionGetterSetterObject {private List<Person> listPeople;public void setListPeople(List<Person> listPeople) {this.listPeople = new ArrayList<Person>(listPeople);}public List<Person> getListPeople() {return new ArrayList<Person>(this.listPeople);}public static void main(String[] args) {CollectionGetterSetterObject collectionGetterSetterObject = new CollectionGetterSetterObject();List<Person> list = new ArrayList<>();list.add(new Person("zhandonghong"));list.add(new Person("jay"));list.add(new Person("vae"));list.add(new Person("eason"));collectionGetterSetterObject.setListPeople(list);System.out.println("List 1:" + list);list.get(2).setName("xusong");List<Person> list1 = collectionGetterSetterObject.getListPeople();System.out.println("list 2:" + list1);list1.get(0).setName("zdh");List<Person> list2 = collectionGetterSetterObject.getListPeople();System.out.println("List 3:" + list2);}
}

对象集合的正确封装
在上面的基础上修改Getter、Setter,并且自定义复制克隆Person对象方法

    private List<Person> listPeople = new ArrayList<>();
//    private List<Person> listPeople;public void setListPeople(List<Person> listPeople) {for (Person person : listPeople) {this.listPeople.add((Person) person.clone());}}public List<Person> getListPeople() {List<Person> list = new ArrayList<>();for (Person person : this.listPeople) {list.add((Person) person.clone());}return list;}

clone.method

    public Object clone() {Person aClone = new Person(this.name);return aClone;}

为自己的类型实现getter和setter

class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public String toString() {return this.name;}public Object clone() {Person aClone = new Person(this.name);return aClone;}
}

Getter和Setter是什么?有什么作用?实现多种数据类型的Getter、Setter方法?实现Getter、Setter的常见的错误?相关推荐

  1. android getter不起作用,java - 如何在Android Studio中自动生成getter和setter

    java - 如何在Android Studio中自动生成getter和setter Android Studio中是否有一个快捷方式可以自动生成给定类中的getter和setter? 14个解决方案 ...

  2. 数据类型的作用及基本数据类型分类

    数据类型的作用及基本数据类型分类 作用 为了限制变量中所存储的数据(至少是可以兼容的). 为了限制变量所占空间 分类 数据类型可分为基本数据类型和引用数据类型.基本数据类型又可分为整型.浮点型.字符型 ...

  3. AutoCAD 出现“安全系统(软件锁许可管理器)不起作用或未正确安装”的解决方法

    AutoCAD 出现"安全系统(软件锁许可管理器)不起作用或未正确安装"的解决方法 参考文章: (1)AutoCAD 出现"安全系统(软件锁许可管理器)不起作用或未正确安 ...

  4. htaccess不起作用的解决方法,AllowOverride All打开后出现403错误时解决办法

    htaccess不起作用的解决方法,AllowOverride All打开后出现403错误时解决办法 参考文章: (1)htaccess不起作用的解决方法,AllowOverride All打开后出现 ...

  5. c语言不同类型变量用什么表示什么作用,C语言数据类型及变量整理

    数据类型 获取int的字节数大小方法 printf("int bytes:%d",sizeof(int)); 列表整理 Int 与 long int的区别 早期的C平台是16位in ...

  6. unity 关于使用Rigidbody的Addforce但不起作用的一些可能原因以及解决方法

    文章目录 可能原因 + 解决方法 涉及到的API以及分析 文章前半部分会总结性的谈到测试过程中发现的可能原因及解决方法,需要注意的是文章以按下空格角色跳跃作为测试点,后办部分则是展示测试过程中查阅的官 ...

  7. AutoCAD 出现“安全系统(软件锁许可管理器)不起作用或未正确安装”的解决方法...

    感谢高飞鸟提供解决方案. 当AutoCAD或自动桌子公司的其它产品在启动过程中突然停电或其它原因造成操作系统重启时,可能会造成这些产品的许可出错而无法再运行. 一般出错后第一次进入时,会提示你&quo ...

  8. 什么是UPNP协议:UPNP协议作用及启用路由器UPNP支持的方法详细介绍

    目录 [隐藏] UPNP简介 基本概念 官网解释 以下是微软官方网站对UPnP的解释: 以下是BC官方网站对UPnP的解释: UPnP是用来干什么的? 经典应用 网络地址转换 NAT 穿越技术 实际应 ...

  9. c语言移位运算的作用,C语言的移位操作符使用方法

    位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算.位移位运算符分为左移和右移两种,均为双目运算符.第一运算对象是移位对象,第二个运算对象是所移的二进制位数.以下是小编为大家搜索整理 ...

最新文章

  1. 用shell脚本配置oracle安装需求
  2. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、使用set_minor_locator函数指定坐标轴次刻度数值倍数(MultipleLocator)
  3. C++ [](){} 匿名函数 lambda表达式
  4. Maven学习(八)继承和聚合
  5. 更适合程序员使用的Vim配置 显示行号 语法高亮 智能缩进
  6. HTTP 状态码常用对照表
  7. Python自然语言处理中文版-学习笔记
  8. nameof() 到底是编译时还是运行时行为?
  9. CreateThread和_beginthread的区别
  10. kali系统apt设置代理
  11. asp建站系统源码_ASP.NET制造业进销存管理系统源码
  12. linux运维、架构之路-Kubernetes本地镜像仓库+dashboard部署
  13. Flutter 的渲染逻辑及和 Native 通信
  14. LINUX grep忽略排除某些目录、文件
  15. 利用JSP编程技术实现一个简单的购物车程序
  16. uni-app地址四级联动
  17. 计算机科学与技术专业自我小结,最新计算机科学与技术专业毕业自我个人小结优秀范文原创...
  18. poco mysql 中文_Poco数据库操作用户手册(一)
  19. True Liars (POJ - 1417)带权并查集+dp路径
  20. 苹果怎么下第二个微信_封面苹果手机微信聊天记录怎么恢复?

热门文章

  1. CAShapeLayer和UIBezierPath
  2. RTSP协议视频监控智能分析平台EasyNVR如何将音频转化为aac格式并上传?
  3. 15.unsafe类的CAS是怎么保证原子性的?
  4. 笔记:C#_对象池_异常代码: c0000005
  5. 四极管:WaitForMultipleObjects的疑惑
  6. Foxmail邮箱通讯录导入方案
  7. 星际文件系统优点和原理
  8. 北大计算机系研究生宿舍地址,北京大学研究生宿舍
  9. 基于微信小程序的自来水收费系统设计与实现-计算机毕业设计源码+LW文档
  10. 聪明的数据结构和笨拙的逻辑代码