get()和set()方法在保护类安全性上的意义

发布时间 2023-05-05 09:51:18作者: 过情关

1、起因

如果为一个private变量设置了get()和set()方法,不就是相当于其为public变量吗?这样做是不是过于繁琐了?

如果对形如下方的简单代码而言,可以说是上面的疑惑是对的

public class SimpleGetAndSet {
    private int n;

    public SimpleGetAndSet(int n) {
        this.n = n;
    }

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }
}

2、意义

然而既然Java有这样的规范,必有其存在的意义。

2.1、类安全性


从类安全角度出发,考虑以下场景,我们需要维持一个范围对象Range,其应该满足成员变量lower小于等于upper恒成立,这样才是一个合法的范围。

倘若直接将Range类如下定义,不难发现会有以下问题:如果用户没有按照规则设置lowwer与upper,那么将会导致出现错误的范围

public class Range {
    public int lower;
    public int upper;

    public Range() {
    }
}

这样的问题对于无论是sdk或是框架或是产品等是不可接受的,我们不能保证用户一定会合法地使用Range类,不合法的使用有可能对类的安全性乃至系统的安全性造成威胁。

我们可以这样来完善:(重点关注set方法)

public class SafeRange {
    private int lower;
    private int upper;

    public SafeRange(int lower,int upper) {
        if (lower > upper) {
            try {
                throw new Exception("Lower is larger than upper");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.lower=lower;
        this.upper=upper;
    }

    public int getLower() {
        return lower;
    }

    public void setLower(int lower) {
        if (lower > upper) {
            try {
                throw new Exception("Lower is larger than upper");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.lower = lower;
    }

    public int getUpper() {
        return upper;
    }

    public void setUpper(int upper) {
        if (upper < lower) {
            try {
                throw new Exception("Upper is larger than lower");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.upper = upper;
    }
}

在两个set方法中,我们检查了upper和lower的合法性,这样一来在用户使用时,构造出的SafeRange一定满足lower<=upper。

顺带一提,这里的安全性没有涉及到多线程环境下的安全性,如果在多线程环境下,应该再加上synchronize关键字。

2.2、解耦


如果我们是内部人员使用,并且都知晓lower<=upper的规则,在使用Range类时会加上检查语句,那么是不是就可以任然采用原Range类的设计呢?

显然是不能的,考虑以下情况:

某一天,Range类的约束变为了lower<upper(少了等号),那么如果采用原来Range类的设计,我们需要在所有使用到它的地方改变检查语句!这显然是不可行的,会带来巨大的工作量并且不难以确保所有使用到的地方都被修改。

而倘若使用SafeRange类,我们只需要在其set()方法上稍作修改即可。

显然,set()方法在这里提供了解耦的效果