Java——不可变类

可以遵照以下几点来编写一个不可变类:
1. 类应该定义成final,避免被继承。将类声明为final (强不可变类),或者将所有类方法加上final(弱不可变类)。或者使用静态工厂并声明构造器为private。
2. 声明属性为 private 和 final 。
3. 不要提供任何可以修改对象状态的方法:不仅仅是set方法,还有任何其它可以改变状态的方法。
4. 如果类有任何可变对象属性,那么当它们在类和类的调用者间传递的时候必须被保护性拷贝。如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
注意:get 方法不要把类里的成员变量让外部客户端引用,当需要访问成员变量时,返回成员变量的copy。构造函数不要引用外部可变对象,如果需要引用可以在外部改变值的变量,应该在构造函数里进行defensive copy。

使用场景
不可变类最适合表示抽象数据类型(如数字、枚举类型或颜色)的值。
另一个适合用不可变类实现的好示例就是 事件 。事件的生命期较短,而且常常会在创建它们的线程之外的线程中消耗,所以使它们成为不可变的是利大于弊。同样地,在 通信系统的 组件间 进行 消息传递,将消息对象设计成不可变的是明智的。
但有的时候String的immutable特性也会引起安全问题,这就是密码应该存放在字符数组中而不是String中的原因!
1. 由于String在Java中是不可变的,如果你将密码以明文的形式保存成字符串,那么它将一直留在内存中,直到垃圾收集器把它清除。而由于字符串被放在字符串缓冲池中以方便重复使用,所以它就可能在内存中被保留很长时间,而这将导致安全隐患,因为任何能够访问内存(memory dump内存转储)的人都能清晰的看到文本中的密码,这也是为什么你应该总是使用加密的形式而不是明文来保存密码。由于字符串是不可变的,所以没有任何方式可以修改字符串的值,因为每次修改都将产生新的字符串,然而如果你使用char[]来保存密码,你仍然可以将其中所有的元素都设置为空或者零。所以将密码保存到字符数组中很明显的降低了密码被窃取的风险。
2. Java本身也推荐使用JPasswordField组件的getPassword()方法,该方法将返回一个字符数组,而放弃了原来的getText()方法,这个方法把密码以明文的形式返回而可能会引起安全问题。
这就是为什么使用字符数组存储密码比字符串更好的原因。只使用字符数组也是不够的,为了更安全你需要将数组内容进行转化。建议使用哈希的或者是加密过的密码而不是明文,然后一旦完成验证,就将它从内存中清除掉。

猜你喜欢

转载自blog.csdn.net/Mr_Effiya/article/details/84330511