• Java


    不可变类,即实例不能被修改的类,实例中包含的所有信息在对象的生命周期内固定不变。
    常见的比如String、基本类型的封装类、BigDecimal、BigInteger。

    相对与可变类,不可变更易于设计、实现、使用,且更稳定(less prone to error)更安全。 比如,不可变类本质上就是线程安全的,不需要做同步处理,使用起来也非常方便。


    设计不可变类,我们有5个原则

    • 不提供任何可修改对象状态的方法。(这种方法也成为mutator,相应词汇"可变性(mutability)")
    • 保证类不会被扩展(extends),以防止通过子类修改对象状态。防止扩展的方式通常是用final修饰。
    • 尽量使所有的field加上final修饰。
    • 尽量使所有的field都是private。虽然给一个基本类型或者指向不可变引用的field加上final可以防止直接修改field,但我们还需要考虑在以后的版本中变更field的表示法。
    • Ensure exclusive access to any mutable components.
      即,如果一个field指向可变对象,则需要防止用户直接获得该可变对象。可以通过在构造器、getter、readObject中返回对象的拷贝的方式解决这一问题。


    以书中代码为例,这是一种典型的不可变类:

    public final class Complex {
        private final double re;
        private final double im;
    
        public Complex(double re, double im) {
            this.re = re;
            this.im = im;
        }
    
        // Accessors with no corresponding mutators
        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;
            // See page 43 to find out why we use compare instead of ==
            return Double.compare(re, c.re) == 0 && Double.compare(im, c.im) == 0;
        }
    
        @Override
        public int hashCode() {
            int result = 17 + hashDouble(re);
            result = 31 * result + hashDouble(im);
            return result;
        }
    
        private int hashDouble(double val) {
            long longBits = Double.doubleToLongBits(re);
            return (int) (longBits ^ (longBits >>> 32));
        }
    
        @Override
        public String toString() {
            return "(" + re + " + " + im + "i)";
        }
    }
    


    鉴于不可变对象本质上就是线程安全的,不可变对象可以自由地进行传递,根本不用考虑在构造器或者getter中进行实例拷贝。
    但正如上面的代码,使用不可变类的方法改变其自身状态时都要返回一个单独的对象。
    如果创建对象的开销较大,这将有可能导致性能问题。


    站在类提供者的立场上,我们有两种方法可以解决这一问题:

    • 在类内部使用的操作尽量使用基本类型。
    • 如果可以预想到那些状态经常会改变,则相应提供一个包级私有的配套类,比如,StringBuilder相对于String。


    另外,如果因为某种原因不能使用final修饰不可变类,但又不希望被扩展,除了使用final是否还有其他方法。
    方法就是,使用public static工厂方法取代所有public构造器。
    比如:

    public static Complex valueOf(double re, double im) {
        return new Complex(re, im);
    }
    
    public static Complex valueOfPolar(double r, double theta) {
        return new Complex(r * Math.cos(theta), r * Math.sin(theta));
    }
  • 相关阅读:
    字符数组(判断字符串大小)
    http请求文件流
    webservice接口调用
    面试基础-线程(一)
    面试基础-redis(二)
    面试基础-redis(一)
    面试基础--JVM
    【转】支付系统
    springcloud搭建高可用注册中心的时候注册中心在unavailable-replicas中的问题
    springboot+javafx所有依赖一起打包
  • 原文地址:https://www.cnblogs.com/kavlez/p/4251292.html
Copyright © 2020-2023  润新知