小论Java类变量的隐私泄露

什么是类变量的隐私泄露

在面向对象编程的过程中,一个特定的类A往往含有一些私有变量。对于私有变量,我们往往会设置其封装字段为“private”,并且设置get函数和set函数,希望其他类能且仅通过类A的get函数和set函数去更改这些私有变量。

然而,有的时候,其他类B中可能包含了表示A类的对象以及包含了能够修改A类私有属性的方法,或称B和A构成复合(B has A)关系,此时,我们在调用类B的过程中就有可能改变类A的私有属性,这就称为“隐私泄露”(privacy leak)。

举个栗子

现有一个“银行”类如下:(A类)

public class Bank {
    private final String username; //Assume username does not change often.
    private String password;

    public Bank(String username, String password){
        this.username = username;
        this.password = password;
    }//end constructor

    public void setPassword(String pass){
        password = pass;
    }//end method

    @Override
    public String toString(){
        return "Bank: Username: " + username + ", password: " + password;
    }//end method
}//end class

并且,我们设置了一个“用户”类(B类),其中含有修改该用户密码的函数:

public class User {
    private String username;
    private Bank bankAccount;

    public User(String username){
        this(username, null);
    }//end cons

    public User(String username, Bank bank){
        this.username = username;
        this.bankAccount = bank;
    }//end method

    public void resetBankPassword(String newPassword){
        bankAccount.setPassword(newPassword);
    }//end method

    @Override
    public String toString(){
        return "用户:" + username + " " + bankAccount;
    }//end method

}//end class

我们即可发现,通过User类不仅可以改变与当前用户相关账号的密码,还能改变与之不想关任何包含了的类Bank实例化对象的密码,某个示例代码如下(C类):

    public static void main(String[] args) {
        Bank bankAcc1 =  new Bank("银行初始化账户", "123456");
        User user1 = new User("肉鸡", bankAcc1);
        User user2 = new User("傻哥", bankAcc1);

        user1.resetBankPassword("654321");
        System.out.println(bankAcc1);
        System.out.println(user1);
        System.out.println(user2);
    }//end main

bankAcc1只是用来初始化用户的,因此“肉鸡”用户密码的修改不应该连带修改了银行类对象bankAcc1中的密码,更不应该改变“傻哥”账号的密码。因此我们说bankAcc1由于User类对它的调用,其私有变量password产生了“隐私泄露”。

解决之道

当程序对于类型安全有特殊要求时(没要求的话当然随意),我们需要对于调用了其他类A的类B中的函数做出一定修改,使得其他类(C类)不能通过修改B类的方式修改A类的私有变量。其方法就是,我们需要对于A类加一个“克隆构造函数”(copy constructor)。在B类中的函数对于代表A类的变量进行调用时,首先“克隆”一份A类对象原本的映像,再在映像上进行修改,从而使得代表A类的对象属性不变,而B类中相应的属性发生我们希望的变更。针对上述的例子,我们需要做如下修改:

“银行”类(A类)中添加的代码:

    public Bank(Bank orig){
        this.username = orig.username;
        this.password = orig.password;
    }

“用户”类(B类)变更resetBankPassword函数如下:

    public void resetBankPassword(String newPassword){
        bankAccount = new Bank(bankAccount);
        bankAccount.setPassword(newPassword);        
    }//end method

C类调用保持不变,获得以下结果:

此时,我们就在成功变更用户密码时并没有改变初始账号的密码,从而实现了对初始账号私有变量“密码”的隐私保护。

注意:

使用copy constructor确实实现了对于无关类私有变量的隐私保护,然而其实现过程中由于“拷贝”了整个对象的数据,因此会增加额外的内存需求,在某个类的对象包含大量数据且对类型安全无特殊要求时,应当慎用此招。

参考资料:

[1] W. Savitch, Absolute Java. Pearson Addison Wesley 6th Edition, 2013.

转载于:https://my.oschina.net/Samyan/blog/2874702

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值