《Effective Java》阅读笔记 15使可变性最小化

1.不可变类的优势

不可变类只是其实例不能被修改的类。不可变的类比可变类更加易于设计、实现和使用。它们不容易出错,且更加安全。

Java 平台类库包含许多不可变的类,包括 String 类、基本类型包装类以及 BigInteger 类和 BigDecimal 类。 有很多很好的理由:可变类比可变类更易于设计,实现和使用。 他们不容易出错,并且更安全

2.如何设计不可变类

1.不要提供任何会修改对象状态的方法。

2.保证类不会被扩展。

3.使所有的域都是 final 的。

4.使所有的域都是私有的。

5.确保对于任何可变组建的互斥访问。

不可变类实例:

public final class Complex {
private final double re;
private final double im;
	public Complex(double re, double im){
	    this.re = re;
	    this.im = im;}
	public double realPart(){
		return re;
	}
	public double imaginaryPart(){
		return im;
	}
	public Complex add(Complex c){
	    return new Complex(re + c.re, im + c.im);
	}
	public Complex subtract(Complex c){
	    return new Complex(re - c.re, im - c.im);
	}
	public Complex multiply(Complex c){
	    return new Complex(re * c.re - im * c.im, re * c.im + im * c.re);
	}
	public Complex divide(Complex c){
	    double tmp = c.re * c.re + c.im * c.im;
	    return new Complex((re * c.re + im * c.im) / tmp, (im * c.re - re * c.im) / tmp);
	}
	    
	@Override
	public boolean equals(Object o){
	    if (o == this)
	        return true;
	    if (!(o instanceof Complex))
	        return false;
	    Complex c = (Complex)o;
	    return Double.compare(re, c.re) == 0 && Double.compare(im, c.im) == 0;
	}
	
	@Override
	public int hashCode(){
	    int result = 17;
	    result = 31 * result + hashDouble(re);
	    result = 31 * result + hashDouble(im);
	    return result;
	}
	private int hashDouble (double val) {
	    long longBits = Double.doubleToLongBits(re);
	    return (int) (longBits ^ (longBits >>> 32));
	}
}

这个类表示一个复数(具有实部和虚部)。除了标准的Object方法之外,它还提供了针对实部和虚部的访问方法,以及4种基本的算术运算:加法,减法,乘法和除法。注意这些算术运算是创建并返回新的Complex实例,而不是修改这个实例

3.优势

  • 1.不可变对象本质上是 线程安全 的,它们不要求同步

  • 2.不可变类可以 提供一些静态工厂 ,它们把频繁的请求的实例缓存起来,从而当现有实例可以符合请求的时候,就不必创建新的实例

  • 3.“不可变对象 可以被自由的共享” ==> 永远不需要进行保护性拷贝。

  • 4.不仅可以共享不可变对象,甚至也 可以共享它们的内部信息

public class BigInteger {
    public BigInteger negate() {
        return new BigInteger(this.mag, -this.signum);
    }
}

BigInteger 类内部用了符合数值表示法,符合用一个int类型的值来表示,数值则用int数组表示。negate方法产生一个新的BigInteger ,其中数值是一样的,符合是相反的。它并不需要拷贝数组;新建的BigInteger 也指向原始实例中的同一个内部数组。

  • 5.不可变对象 为其他对象提供了大量的构件,无论是可变的还是不可变的。

4.缺点

对于每一个不同的值都需要一个单独的对象

如果你执行一个多步骤的操作,并且每个步骤都会产生一个新的对象,除了最后的结果之外其他的对象最终都会被丢弃,此时性能问题就会显露出来。

5.如何优化

  • 1.使类是 final 的。

  • 2.让类的所有构造器都是私有的或者包级私有的并添加公有的静态工厂来代替公有构造器。

  • 3.坚决不要为每个 get 方法都提供一个 set 方法。

  • 4.构造器应该创建完全初始化的对象,不要在构造器或者静态工厂之外再提供公有的初始化方法, 除非有令人信服的理由必须这么做。

  • 5.如果有的类不能做成不可变的,应该尽可能的限制它的可变性。

  • 6.如果不可变类要实现 Serilizable 接口,并且它包含一个或者多个指向可变对象的域,就必须提供一个显示的 readObject 或者 readResolve 方法。(或者使用 ObjectOutputStream.writeUnshared 和ObjectInputStream.readUnshared 方法)否则有可能通过序列号再反序列化会使不可变的类创建可变的实例。

示例

public class ComplexOther {
	private final double re;
	private final double im;
	
	private ComplexOther(double re,double im) {
		this.re = re;
		this.im = im;
	}
	
	public static ComplexOther getInstance(double re,double im) {
		return new ComplexOther(re,im);
	}
}

这种方式的好处:

  • 1.允许使用多个包级实现类

  • 2.可以提供缓存能力

  • 3.具有静态工厂的优势,可以清楚的表明它的功能。

6.结论

不可变类有很多好处,因此合适的适用场景下,可以考虑将类设计生不可变类,除非是真的有必要换成可变类。可变类也需要尽量将可变性设置为最小。;

7.参考文献

https://blog.csdn.net/xl890727/article/details/80252751
《Effective Java》
https://www.jianshu.com/p/2293d0e7a0df
在这里插入图片描述

本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!

1.计算机网络----三次握手四次挥手
2.梦想成真-----项目自我介绍
3.你们要的设计模式来了
4.一字一句教你面试“个人简介”
5.接近30场面试分享

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haikuotiankongdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值