文章地址: https://dzone.com/articles/java-getter-and-setter-basics-common-mistakes-and
Getter and setter are widely used in Java. It is seemingly simple, but not every programmer understands and implements this kind of method properly. So in this article, I would like to deeply discuss getter and setter methods in Java — from the basics to common mistakes and best practices.
If you are already good with the basics, jump directly to section 4 where I talk about common mistakes and best practices.
You may also like: Why Should I Write Getters and Setters?
1. What Are Getter and Setter?
In Java, getter and setter are two conventional methods that are used for retrieving and updating the value of a variable.
The following code is an example of a simple class with a private variable and a couple of getter/setter methods:
The class declares a private variable, number. Since number is private, the code from the outside of this class cannot access the variable directly, as shown below:
Instead, the outside code has to invoke the getter, getNumber()
, and the setter, setNumber()
, in order to read or update the variable, for example:
So, a setter is a method that updates the value of a variable. And a getter is a method that reads the value of a variable. Getter and setter are also known as accessor and mutator in Java.
2. Why Do We Need Getter and Setter?
By using getter and setter, the programmer can control how their important variables are accessed and updated in the proper manner, such as changing the value of a variable within a specified range. Consider the following code of a setter method:
This ensures that the value of the number is always set between 10 and 100. Suppose the variable number can be updated directly, the caller can set any arbitrary value to it:
And that violates the constraint for values ranging from 10 to 100 for that variable. Of course, we don’t expect that to happen. Thus, hiding the variable number as private and then using a setter comes to the rescue.
On the other hand, a getter method is the only way for the outside world to read the variable’s value:
The following picture illustrates the situation:
So far, the setter and getter methods protect a variable’s value from unexpected changes by the outside world — the caller code.
When a variable is hidden by the private modifier and can be accessed only through getter and setter, it is encapsulated. Encapsulation is one of the fundamental principles in object-oriented programming (OOP), thus implementing getter and setter is one of the ways to enforce encapsulation in the program’s code.
Some frameworks such as Hibernate, Spring, and Struts can inspect information or inject their utility code through getter and setter. So providing getter and setter is necessary when integrating your code with such frameworks.
3. Naming Convention for Getter and Setter
The naming scheme of setter and getter should follow the Java bean naming convention as getXxx()
and setXxx()
, where Xxx
is the name of the variable. For example, with the following variable name:
The appropriate setter and getter will be:
If the variable is of the type boolean, then the getter’s name can be either isXXX()
or getXXX()
, but the former naming is preferred. For example:
The following table shows some examples of getters and setters which qualified for the naming convention:
Variable declaration |
Getter method |
Setter method |
int quantity
|
|
|
string firstName
|
|
|
Date birthday
|
|
|
boolean rich
|
|
|
4. Common Mistakes When Implementing Getter and Setter
People often make mistakes, and developers are no exception. This section describes the most common mistakes when implementing setters and getters in Java, as well as workarounds.
Mistake #1: You have setter and getter, but the variable is declared in a less restricted scope.
Consider the following code snippet:
The variable firstName
is declared as public, so it can be accessed using the dot (.) operator directly, making the setter and getter useless. A workaround for this case is using more restricted access modifier such as protected and private:
In the book Effective Java, Joshua Bloch points out this problem in item 14:
"In public classes, use accessor methods, not public fields."
Mistake #2: Assign object reference directly in the setter
Considering the following setter method:
The following code demonstrates this problem:
An array of integer numbers, myScores
, is initialized with 6 values (line 1) and the array is passed to the setScores()
method (line 2). The method displayScores()
simply prints out all scores from the array:
Line 3 will produce the following output:
These are all the elements of the myScores
array. Now, in line 4, we can modify the value of the 2nd element in the myScores
array as follows:
What will happen if we call the method displayScores()
again at line 5? Well, it will produce the following output:
You realize that the value of the 2nd element is changed from 5 to 1, as a result of the assignment in line 4. Why does it matter? Well, that means the data can be modified outside the scope of the setter method, which breaks the encapsulation purpose of the setter. And why does that happen? Let’s look at the setScores()
method again:
The member variable scores are assigned to the method’s parameter variable scr
directly. That means both of the variables are referring to the same object in memory — the myScores
array object. So changes made to either the scores
or myScores
variables are actually made on the same object.
A workaround for this situation is to copy elements from the scr
array to the scores
array, one by one. The modified version of the setter would look like this:
What’s the difference? Well, the member variable scores
is no longer referring to the object referred by the scr
variable. Instead, the array scores
is initialized to a new one with size equals to the size of the array scr
. Then, we copy all elements from the array scr
to the array scores
, using System.arraycopy()
method.
Run the following example again, and it will give us the following output:
Now, the two invocations of displayScores()
produce the same output. That means the array scores
is independent and different than the array scr
passed into the setter, thus we have the assignment:
This does not affect the array scores
.
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 the System.arraycopy()
method.
Mistake #3: Return the object reference directly in getter
Consider the following getter method:
And then look at the following code snippet:
It will produce the following output:
As you notice, the 2nd element of the array scores
is modified outside the setter, in line 5. Because the getter method returns the reference of the internal variable scores directly, the outside code can obtain this reference and make a change to the internal object.
A workaround for this case is that, instead of returning the reference directly in the getter, we should return a copy of the object. This is so that the outside code can obtain only a copy, not the internal object. Therefore, we modify the above getter as follows:
So the rule of thumb is: Do not return a reference of the original object in the getter method. Instead, it should return a copy of the original object.
5. Implementing Getters and Setters for Primitive Types
With primitive types (int
, float
, double
, boolean
, char
…), you can freely assign/return values directly in setter/getter because Java copies the value of one primitive to another instead of copying the object reference. So, mistakes #2 and #3 can easily be avoided.
For example, the following code is safe because the setter and getter are involved in a primitive type of float
:
So, for primitive types, there is no special trick to correctly implement the getter and setter.
6. Implementing Getters and Setters for Common Object Types
Getters and Setters for String Objects:
String is an object type, but it is immutable, which means once a String object is created, its String literal cannot be changed. In other words, every change on that String object will result in a newly created String object. So, like primitive types, you can safely implement getter and setter for a String variable, like this:
Getters and Setters for Date Objects:
The java.util.Date
class implements the 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, as shown in the following example:
The clone()
method returns an Object
, so we must cast it to the Date
type.You can learn more about this in item 39 of Effective Java by Joshua Bloch:
"Make defensive copies when needed."
7. Implementing Getters and Setters for Collection Types
As described in mistakes #2 and #3, it’s not good to have setter and getter methods like this:
Consider the following program:
According to the rules for implementing getter and setter, the three System.out.println()
statements should produce the same result. However, when running the above program, it produces the following output:
For a collection of Strings, one solution is to use the constructor that takes another collection as an argument. For example, we can change the code of the above getter and setter as follows:
Re-compile and run the CollectionGetterSetter
program; it will produce the desired output:
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 the Person
object:
It produces the following output when running:
Because unlike String, for which new objects will be created whenever a String object is copied, other Object
types are not. Only references are copied, so that’s why two Collections are distinct but they contain the same objects. In other words, it is because we haven’t provided any means for copying objects.
Look at the Collection API; we found that ArrayList
, HashMap
, HashSet
, etc. implement their own clone()
methods. These methods return shallow copies, which do not copy elements from the source Collection to the destination. According to the Javadoc of the clone()
method of the ArrayList
class:
public Object clone()
Returns a shallow copy of this ArrayList instance.
(The elements themselves are not copied.)
Thus, we cannot use the clone()
method of these Collection classes. The solution is to implement the clone()
method for our own defined object — the Person
class in the above example. We implement the clone()
method in the Person
class as shown below:
The setter for listPeople
is modified as follows:
The corresponding getter is modified, as shown below:
That results in a new version of the class CollectionGetterSetterObject,
shown below:
Compile and run the new version of CollectionGetterSetterObject
; it will produce the desired output:
So, the key points for implementing getter and setter for a Collection type are:
- For a Collection of String objects, it does not need any special tweak since String objects are immutable.
- For a Collection of custom types of an object:
- Implement the
clone()
method for the custom type. - For the setter, add cloned items from the source Collection to the destination one.
- For the getter, create a new Collection, which is being returned. Add cloned items from the original Collection to the new one.
- Implement the
8. Implementing Getters and Setters for Your Own Type
If you define a custom type of object, you should implement the clone()
method for your own type. For example:
As we can see, the class Person
implements its clone()
method to return a cloned version of itself. Then, the setter method should be implemented like below:
And for the getter method:
So, the rules for implementing getter and setter for a custom object type are:
- Implement a
clone()
method for the custom type. - Return a cloned object from the getter.
- Assign a cloned object in the setter.
Conclusion
Java getter and setter seems to be simple, yet it can be dangerous if implemented naively. It could even be a source of problems that cause your code to misbehave. Or worse, one could easily exploit your programs by insidiously manipulating the arguments to, and returned objects from, your getters and setters. So, be careful and consider implementing the best practices mentioned above.
Hope you enjoyed!
Further Reading
Why Should I Write Getters and Setters?
相关推荐
在深入学习Vue框架的过程中,理解和掌握getter和setter机制是非常重要的。Vue通过响应式原理,将普通的JavaScript对象属性转换成getter和setter,以此来实现数据的双向绑定和状态管理。下面我们将详细地探讨Vue中的...
在Java编程中,getter和setter方法是用于封装对象属性的重要工具。Eclipse作为一个强大的集成开发环境(IDE),提供了丰富的代码生成功能,包括自动为getter和setter添加注释。本篇文章将详细探讨如何在Eclipse中...
在JavaScript编程中,"signs_getter_setter"是一个常见的概念,它涉及到对象属性的访问控制和封装。标记常量通常是指将某些变量定义为不可更改的,而Getter-Setter则是一种面向对象编程中的特性,用于获取(get)或...
这个场景中提到的是将一个Java类编译成JSON,但只包含那些具有getter和setter方法的属性。这样的转换有助于减少JSON输出中的冗余信息,只保留与业务逻辑相关的数据。下面我们将深入探讨这个过程。 首先,我们需要...
提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,java * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,java * 反射工具类. 提供调用getter/...
在Java编程中,getter和setter方法是对象属性访问的重要组成部分,它们提供了封装和数据访问控制。为了提高开发效率,IntelliJ IDEA,一款广受欢迎的Java集成开发环境(IDE),提供了一系列的插件来简化getter和...
如何使用它使用 getter/setter 方法创建对象 // Create an object with getter/setter methodvar obj = { name : new getterSetter ( 'John' )} ;// Access the property in read or write modeconsole . log ( obj ...
在Java编程中,getter和setter方法是面向对象设计原则中的封装特性的重要体现。它们用于访问和修改类的私有成员变量,确保数据的安全性。Eclipse是一款广泛使用的集成开发环境(IDE),它提供了丰富的代码自动补全和...
然而,在实际开发过程中,有时我们需要自动生成带有注释的getter和setter方法,以提高代码的可读性和规范性。IDEA默认生成的getter和setter方法可能不包含注释,这可能给团队协作带来不便。本文将详细解释如何配置...
在编程领域,尤其是在Java开发中,getter和setter方法是面向对象设计的重要组成部分,它们用于封装对象的属性,确保数据的安全性。然而,手动编写这些方法可能会耗费大量时间。为了解决这个问题,开发者们通常会利用...
在iOS开发中,getter和setter方法是Objective-C和Swift中对象属性访问的重要组成部分。它们用于获取(get)和设置(set)对象的属性值。本文将深入探讨getter和setter的概念、作用以及如何在代码中使用它们。 首先...
本篇将详细讲解一个名为"Intellij Plugin Expose Javadoc"的插件,它能够帮助开发者将实例变量上的JavaDoc注释自动应用到对应的Getter和Setter方法中,从而提高代码的可读性和维护性。 JavaDoc是一种在Java源代码中...
虽然标题和描述中提到了"C#"和"Java getter setter",但这里我们将主要聚焦于C#中的getter和setter,因为这是给定标签的内容。 C#是一种强大的面向对象的编程语言,它在处理对象属性时提供了getter和setter方法。在...
StarUML扩展,用于生成getter和setter 此扩展允许为选定的属性或选定的类生成获取器和设置器。 安装 打开扩展管理器(工具>扩展管理器),然后选择注册表选项卡,然后在搜索框中输入“ getter”。 您可以找到此扩展...
提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实...
在Java编程语言中,getter和setter方法是面向对象设计的一部分,它们主要用于封装对象的属性,以保护数据并提供访问控制。Eclipse是一款流行的集成开发环境(IDE),它提供了丰富的自动代码生成功能,包括生成getter...
标题中的“自动生成带注释的getter和setter方法(Intellij、AndroidStudio插件)”指的是在编程过程中,开发者可以利用特定的插件自动化生成Java Bean模式中的getter和setter方法,并且这些方法会带有注释。...
本文将深入探讨Vue.js中getter和setter在实现数据双向绑定中的关键作用。 首先,我们要了解在JavaScript中,getter和setter是Object对象的方法,用于在访问或修改对象属性时执行自定义逻辑。getter用于获取属性值,...
VS2005(C#)插件Getter/Setter生成器是一款专为Visual Studio 2005设计的扩展工具,旨在提高C#编程的效率。该插件的主要功能是自动生成属性的getter和setter方法,这在编写面向对象的代码时非常常见。通过自动化这个...
在Java编程中,Eclipse是一款广泛使用的集成开发环境(IDE),它提供了许多便捷的功能,包括自动生成getter和setter方法。这些方法通常用于封装类的属性,以保护数据并实现对象的访问控制。当我们为类的每个字段添加...