Java Getter / Setter "anti-pit Guide" to the

This article from the yanglbme original, starting in public No. " Doocs the open source community ," welcome to reprint.

Getter / Setter is widely used in Java. It seems simple, but not every Java developer can well understand and Getter / Setter methods correctly implemented. Therefore, in this article, I would like to discuss in depth in Java getter and setter methods, please follow me with a look.

A simple example

The following code shows the basic use Getter / Setter methods.

public class GetterAndSetterExample {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
复制代码

You can see, we are in a class GetterAndSetterExampledeclares a private variable name in. Because the name is private, so we can not directly access the variable outside the class. The following code will not compile:

GetterAndSetterExample object = new GetterAndSetterExample();
object.name = "yanglbme"; // 编译出错
String name = object.name; // 编译出错
复制代码

Correct "posture" is to call the getter getName()and setter setName()to read or update the variables:

GetterAndSetterExample object = new GetterAndSetterExample();
object.setName("yanglbme");
String name = object.getName();
复制代码

Why do we need Getter / Setter?

By using Getter / Setter methods to access variables (get) and update (set) will become controllable. Consider the code the following Setter method:

public void setName(String name) {
    if (name == null || "".equals(name)) {
        throw new IllegalArgumentException();
    }
    this.name = name;
}
复制代码

This ensures that the value of the name is always set is not empty. If you can directly .set the value of the operator name, the caller can be freely set to any value name, which violates the non-null constraint name variables.

In other words, Getter / Setter way to ensure that the values of variables from outside (the caller Code) unexpected changes. When a variable is privatewhen modifier hidden and can only be accessed through getter and setter, it is "packaged" up. Packaging is one of the basic features of object-oriented programming (OOP), to achieve Getter / Setter package is one method of performing forced in the program code.

Named constraints Getter / Setter methods

Setter and Getter need to follow the naming Java bean naming convention, such as setXxx()and getXxx(), where Xxx is the name of the variable:

public void setName(String name) { }

public String getName() { } // getter
复制代码

And if the variable is boolean type, then the getter method can be named isXxx () or getXxx (), but prefers to use the former named:

private boolean single;

public boolean isSingle() { } // getter
复制代码

Common Errors Getter / Setter implementation

Error 1: realized Getter / Setter methods, but not strictly limit the scope of variables

As shown in the following code fragment:

public String name; // 使用public修饰

public void setName(String name) {
    this.name = name;
}

public String getName() {
    return name;
}
复制代码

The variable name is declared as public, so we can directly outside the class using the dot .operator to access it, so that the setter and getter invalid. In this case the solution is simple, direct use of more "strict" access modifier, for example, protected and private.

Error two: direct assignment of an object referenced in the Setter

Consider the following Setter method:

public class Student {
    private int[] scores;

    // setter
    public void setScores(int[] scores) {
        this.scores = scores;
    }
    
    public void showScores() {
        for (int score : scores) {
            System.out.print(score + " ");
        }
        System.out.println();
    }
}
复制代码

Is not nothing wrong with feeling? Let's look at the following code:

int[] myScores = {100, 97, 99, 88, 69};
Student yang = new Student();

yang.setScores(myScores);
yang.showScores();
复制代码

It can be seen myScores first integer array is initialized and passed to the setScores()method, then scores for a simple printing produces the following output:

100 97 99 88 69 
复制代码

Now, we modify the value myScores array of two elements, and print the scores again:

myScores[1] = 101;
yang.showScores();
复制代码

Program will output the following:

100 101 99 88 69 
复制代码

And this means that we can modify data outside Setter method, which has clearly defeats the purpose Setter package. Why is this so? Let us look at setScores()methods:

public void setScores(int[] scores) {
    this.scores = scores;
}
复制代码

Member variable scores a direct reference to a variable parameter scores, which means that both variables point to the same object, that memory myScoresarray object. Therefore, changes made to myScores variables will lead directly to the member variable scores are synchronized modified. In this case, the solution is: a copy of the method parameters scores assigned to the member variables scores:

public void setScores(int[] scores) {
    this.scores = new int[scores.length];
    System.arraycopy(scores, 0, this.scores, 0, scores.length);
}
复制代码

Experience : If we are to pass objects as parameters to setter methods, do not directly use simple reference assignment. Instead, we should find some way to assign a value to an internal member variables of an object, such as the use of System.arraycopy()methods to copy elements from one array to another array.

Error three: direct reference to the returned object

Getter consider implementing the following method:

private int[] scores;

public int[] getScores() {
    return scores;
}
复制代码

In the process, we call getScores () method, and modify the value of an element:

int[] myScores = {100, 97, 99, 88, 69};
Student yang = new Student();
yang.setScores(myScores);
yang.showScores();

int[] copyScores = yang.getScores();
copyScores[3] = 520;
yang.showScores();
复制代码

Produces the following output:

100 97 99 88 69 
100 97 99 520 69 
复制代码

As you can see, an array of four elements have been revised to 520. This is due to the internal Getter method returns a reference to a member variable scores, therefore, external code can get a reference to the elements and make changes.

In this case the solution is: should return the copy of the object, rather than directly returns a reference:

public int[] getScores() {
    int[] copy = new int[this.scores.length];
    System.arraycopy(this.scores, 0, copy, 0, copy.length);
    return copy; // 返回副本
}
复制代码

Lessons Learned : Do not return to the original object in the Getter method reference. Instead, it should return a copy of the original object.

Basic types Getter / Setter Method

In Java, the basic types int, float, double, boolean, char ..., you can directly set free or return value, because Java is to copy the value of a basic variable to another variable, instead of copying objects references, therefore, wrong two or three can be easily avoided.

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

In other words, the basic data types, do not need special skills to achieve the correct Getter / Setter's.

To achieve the object type Getter / Setter Method

Getter String object / Setter methods

String is a type of object, but it is immutable, meaning that once we String object is created, it can not change its contents. In other words, the String object of each change will result in a newly created String object. So, like primitive types, we can safely achieve Getter / Setter as String variables, like this:

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

Getter Date object / Setter Method

java.util.DateClass implements clone () method of class Object. method returns a copy of the object clone (), so we can use it for the setter and getter, as the following code:

private Date birthDate;
public void setBirthDate(Date birthDate) {
    this.birthDate = (Date) birthDate.clone();
}
public Date getBirthDate() {
    return (Date) this.birthDate.clone();
}
复制代码

clone() The method returns an object of type Object, so we must be cast to type Date.

Getter Collection object / Setter Method

For Collection object, as error two, three described above, so that we can not simply achieved Getter / Setter method.

private List<String> listTitles;
public void setListTitles(List<String> titles) {
    this.listTitles = titles;
}
public List<String> getListTitles() {
    return listTitles;
}
复制代码

For a collection of strings A solution is to use a constructor function to receive another set of parameters as constructor. such as:

public void setListTitles(List<String> titles) {
    // 将titles传递给ArrayList的构造函数
    this.listTitles = new ArrayList<String>(titles);
}
public List<String> getListTitles() {
    return new ArrayList<String>(this.listTitles);   
}
复制代码

Note that , the above configuration method is only applicable to the collection of string . But not for the collection of type Object. Consider the following example, we define the class CollectionGetterSetterObjectand Person:

import java.util.*; 
public class CollectionGetterSetterObject {
    // 元素类型是Person的List集合
    private List<Person> listPeople; 
    public void setListPeople(List<Person> list) { 
        this.listPeople = new ArrayList<Person>(list); 
    } 
    public List<Person> getListPeople() { 
        return new ArrayList<Person>(this.listPeople); 
    } 
} 

class Person { 
    private String name; 
    public Person(String name) { 
        this.name = name; 
    } 
    public String getName() { 
        return name; 
    } 
    public void setName(String name) { 
        this.name = name; 
    } 
    public String toString() { 
        return name; 
    } 
}
复制代码

For String, a String object each copy will be created for the new object, and other objects of type Object is not, copy them only references, so this is two different sets of objects they contain the same reason.

View Collection API, we found ArrayList, HashMap, HashSet and other implements its own clone () method. These methods return a shallow copy, these are not shallow copy of the elements copied from the source to the target Collection.

For example, Javadoc clone ArrayList class () method is described as follows:

/**
 * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
 * elements themselves are not copied.)
 *
 * @return a clone of this <tt>ArrayList</tt> instance
 */
public Object clone() { }
复制代码

Therefore, we can not use these clone Collection classes () method. The solution is to implement the clone object (Person class in the previous example) our own definition () method. We re-implement clone () method in the Person class, as follows:

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

The method should listPeople Setter modified as follows:

public void setListPeople(List<Person> list) {
    for (Person aPerson : list) {
        this.listPeople.add((Person) aPerson.clone());
    }
}
复制代码

Correspondingly, Getter method should be modified as follows:

public List<Person> getListPeople() {
    List<Person> listReturn = new ArrayList<Person>();
    for (Person aPerson : this.listPeople) {
        listReturn.add((Person) aPerson.clone());
    }
    return listReturn;
}
复制代码

Therefore, the new CollectionGetterSetterObjectclass code should look like this:

import java.util.*;
public class CollectionGetterSetterObject {
    private List<Person> listPeople = new ArrayList<Person>();
    public void setListPeople(List<Person> list) {
        for (Person aPerson : list) {
            this.listPeople.add((Person) aPerson.clone());
        }
    }
    public List<Person> getListPeople() {
        List<Person> listReturn = new ArrayList<Person>();
        for (Person aPerson : this.listPeople) {
            listReturn.add((Person) aPerson.clone());
        }
        return listReturn;
    }
}
复制代码

Summary of what, implementation of the Collection type Getter / Setter key points are:

  • String object for collection, since the String object is immutable, and therefore does not require any special adjustments.
  • For a custom type object set:
    • Implement a custom type clone () method.
    • For setter, to clone a collection of items to add collection from source to target.
    • For getter, create a new Collection, and return it. Add the original clone items in the collection to the new collection.

Since Getter / Setter method definition object

If you define custom type object, you should implement clone () method for their type.


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;
    }

    // 自己实现clone方法
    public Object clone() {
        Person aClone = new Person(this.name);
        return aClone;
    }
}
复制代码

As we have seen, Person class implements its clone () method to return to its own clone. Then, setter method should be implemented as follows:

public void setFriend(Person person) {
    this.friend = (Person) person.clone();
}
复制代码

For getter methods:

public Person getFriend() {
    return (Person) this.friend.clone();
}
复制代码

Summary of what, as a custom object type implements getter and setter rules are:

  • Implement a custom type clone () method.
  • It returns an object cloned from getter.
  • Assignment of a clone in the setter.

to sum up

Java-Getter / Setter looks very simple, but if achieved improperly, can be dangerous, it may even be the root cause of your problem of abnormal behavior codes. Or worse it is that people can derive and manipulate objects through implicit parameters Getter or Setter to easily "torn" your program.

Use with caution, to avoid stepping pit.

Guess you like

Origin juejin.im/post/5d9b25865188250969774e64