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

什么是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;
    }
}
  • 5
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值