zoukankan      html  css  js  c++  java
  • String 和 Stringbuild

    什么是不可变类

    下面这段来自[java中的不可变类](https://www.cnblogs.com/zhiheng/p/6653969.html)
    

    先来看一下可变类和不可变类。

    • 不可变类(Immutable Objects):当类的实例一经创建,其内容便不可改变,即无法修改其成员变量。

    • 可变类(Mutable Objects):类的实例创建后,可以修改其内容。

    不可变类的优势 :

    • 效率

    当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小)只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。 此外,不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。

    • 线程安全

    在多线程情况下,一个可变对象的值很可能被其他进程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况同时省去了同步加锁等过程,因此不可变类是线程安全的。

    在《java concurrency in practice》一书给出了一个粗略的定义:对象一旦创建后,其状态不可修改,则该对象为不可变对象。一般一个对象满足以下三点,则可以称为是不可变对象:

    • 其状态不能在创建后再修改;
    • 所有域都是final类型;
    • 其构造函数构造对象期间,this引用没有泄露。

    String 为什么是不可变类

    例子

    String s= "abcd";
    s = "abcdel";
    

    图片出处见参考资料。 1297993-20200318141640096-1992387794.jpg

    底层

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    
        /** Cache the hash code for the string */
        private int hash; // Default to 0
    
        /** use serialVersionUID from JDK 1.0.2 for interoperability */
        private static final long serialVersionUID = -6849794470754667710L;
    
        ....
    
    }
    
    

    可以看到String 维护的 char数组是private final 的。假如我们要是可以修改char里的内容那么,String 肯定就不是不可变类了,例如下面这种操作。

    final int[] value={1,2,3}
    value[2]=100; //更改了第三个元素的值
    
    

    ** 但是String中没有提供方法对char 数组进行更改,所以String这个字符串保证了不可变。 **

    String 作为不可变类安全优势的例子

    public final class  Fa {
        private int num;
    
        public static String stringAdd(String s){
            s += "bbb";
            return s;
    
        }
    
        public static StringBuilder stringBAdd(StringBuilder s){
            s .append("bbb");
            return s;
    
        }
    
    
        public Fa(int num) {
            this.num = num;
        }
    }
    
    
    
    
            String s = "s1";
            String result = Fa.stringAdd(s);
            System.out.println("result : " + s);
    
    
            StringBuilder sb = new StringBuilder("sb");
            String sbResult = Fa.stringBAdd(sb).toString();
            System.out.println("sbResult : " + sb);
    
    
            结果 : 
            result : s1
    		sbResult : sbbbb
    
    

    所以我们建议在当大量使用是字符串的时候使用 stringbuild 可以提高性能,不然新创建的String 对象会占用堆空间,可能导致频繁GC。

    真的是不可变类吗

    实际可以通过反射来获取char数组,从而知道了String的值,这也是很多开发中密码这类属性不建议使用String而是使用char数组的原因。当然开发中很少使用反射去这样获取。

    补充

    final 关键字

    修改变量

    final修饰常量必须为常量赋初始化值,例如 :

    public  class  Fa {
        private int num;
    
        //编译出错
        private  final  int finalTest;
    
        //编译出错
        private final  Zi zi;
    
        public Fa(int num) {
            this.num = num;
        }
    }
    
    

    修饰 class

    修饰某个class 则是不能被继承

    修改对象

    修饰对象则不能更改引用,什么意思呢?

            final Fa f3 = new Fa(3);
            //编译出错
            f3 = new Fa(4);
    
    

    参考资料

    • https://www.cnblogs.com/zhiheng/p/6653969.html
    • https://www.zhihu.com/question/20618891/answer/114125846
  • 相关阅读:
    【ybtoj】【Hash】回文子串
    Design Pattern:状态模式
    Design Pattern:装饰者模式
    Design Pattern:外观模式
    Design Pattern:适配器模式
    Design Pattern:模板方法模式
    Design Pattern:命令模式
    Design Pattern:观察者模式
    Design Pattern:复合模式
    Design Pattern:迭代器模式
  • 原文地址:https://www.cnblogs.com/Benjious/p/12517319.html
Copyright © 2011-2022 走看看