zoukankan      html  css  js  c++  java
  • 聊聊JAVA中 String类为什么不可变

    前言

    "我的风格比较偏传统和经典" 小明说,"我们在打扮自己的问题上还是蛮冒险的...我觉得当你是只狗的时候,穿什么都hold的住!"

    哈哈哈,脱离单身狗快两年了,生活中除了爱情,不变的还有对代码的挚爱,总之始于热爱,忠于爱情,陷于代码。

    前半年规划人生,后半年开始规划,最近发生的一些事情还是让自己倍感压力的,生活可以知足常乐,但人生不可以,如果你不把生命体验到极致,也许会被未来的自己所鄙视。

    前世今生

    String不可变这个话题应该是老生长谈了,你可以说它就是设计者的龟腚,然后巴拉巴拉说出一大堆优点,也可以说它忠于爱情,只要JVM存活,它便万年不变。

    String自打娘胎一出生就跟他们的兄弟姐妹不一样,好好的娃被戴了一个final的帽子,以至于byte,int,short,long等基本类型的小伙们都不带它玩。

    但是,String并不是一个简单的人设,如果各位小伙伴们仔细查阅其源码,那可是浩浩荡荡的3000+行代码了,如果你一个controller能这样的代码量也是非常不错的。

    如果你仔细阅读源码注释,你会发现这样一句话:

    Strings are constant; their values cannot be changed after they are created

    大致意思就是String是个常量,从一出生就注定不可变。

    我觉得到这里各位小伙们应该就知道为什么String不可变了,戴了个final的帽子,官方注释说明创建后不能被改变,但是为什么String要使用final修饰呢?

    面试精选

    在了解String不可变之前,我觉得有必要分析一道经典的面试题:

    public class Apple {
    	public static void main(String[] args) {
            String a = "abc";
            String b = "abc";
            String c = new String("abc");
            System.out.println(a==b);
            System.out.println(a.equals(b));
            System.out.println(a==c);
            System.out.println(a.equals(c));
    	}
    }
    

    答案是:true、true、false、true

    如图所示,代码中的abc对应个的abc:

    我觉得有必要把a、b、c替换成小明、红、光,abc替换成红苹果重新梳理一下流程:

    1. 小明想吃红苹果,小明的爸爸首先会在树上寻找是否有红苹果,有的话,爸爸就说,这个苹果归你了,如果没有,假设万能的小明爸爸也可以给他造一个。

    2. 这时候小红过来了,爸爸我也想吃那个红苹果,并且强烈要求要拿一个,就这样小明和小红共享了这个苹果。

    3. 小光是个听话的孩子,只要是红苹果就行,我可不想跟他俩争什么,爸爸就这样从超市里给小光买了一个红苹果。

    4. 小明和小红的是同一个苹果,这个是不变的事实,无论你怎么比较。

    5. 小红,小明和小光的都是红苹果,但却不是同一个苹果。

    6. 你可以把苹果树理解成常量池,爸爸购买苹果的过程理解为new对象,当然,举例可能不是太恰当,只是为了大家更好的理解。

    回到代码本来来说,因为String太过常用,JAVA类库的设计者在实现时做了个小小的变化,即采用了享元模式,每当生成一个新内容的字符串时,他们都被添加到一个共享池中,当第二次再次生成同样内容的字符串实例时,就共享此对象,而不是创建一个新对象,但是这样的做法仅仅适合于通过=符号进行的初始化。

    需要说明一点的是,在object中,equals()是用来比较内存地址的,但是String重写了equals()方法,用来比较内容的,即使是不同地址,只要内容一致,也会返回true,这也就是为什么a.equals(c)返回true的原因了。

    不可变的好处

    首先,我们应该站在设计者的角度思考问题,而不是觉得这不好,那不合理:

    • 可以实现多个变量引用堆内存中的同一个字符串实例,避免创建的开销。

    • 我们的程序中大量使用了String字符串,有可能是出于安全性考虑。

    • 大家都知道HashMap中key为String类型,如果可变将变的多么可怕。

    • 当我们在传参的时候,使用不可变类不需要去考虑谁可能会修改其内部的值,如果使用可变类的话,可能需要每次记得重新拷贝出里面的值,性能会有一定的损失。

    其次,我们再分析有没有更好的解决方案:

    • 然,对于我来说,并没有!!!
    • 然,对于我来说,并没有!!!
    • 然,对于我来说,并没有!!!

    总结

    了解到String是不可变的,知道了常量池是怎么个东西。

    重温了面试题,有兴趣的小伙伴也可以去阅读下String的源码,浩浩荡荡的3000+。

    String 被new时是要创建对象的,+ 号拼接同理,程序中尽量不要使用 + 拼接,推荐使用StringBuffer或者StringBuilder。

  • 相关阅读:
    NestingQuery
    Repeat
    GenericQuery
    StringOpr
    RHEL5.6 安装 virtualbox
    DNS的资料总结
    drop delete truncate 区别
    Linux Shell命令ulimit的用法
    OSI及TCP/IP的概念和区别
    shell:读取文件的每一行内容并输出
  • 原文地址:https://www.cnblogs.com/smallSevens/p/7550001.html
Copyright © 2011-2022 走看看