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。

  • 相关阅读:
    稳扎稳打Silverlight(47) 4.0UI之操作剪切板, 隐式样式, CompositeTransform, 拖放外部文件到程序中
    返璞归真 asp.net mvc (9) asp.net mvc 3.0 新特性之 View(Razor)
    返璞归真 asp.net mvc (6) asp.net mvc 2.0 新特性
    稳扎稳打Silverlight(48) 4.0其它之打印, 动态绑定, 增强的导航系统, 杂七杂八
    精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First
    稳扎稳打Silverlight(42) 4.0控件之Viewbox, RichTextBox
    稳扎稳打Silverlight(53) 4.0通信之对WCF NetTcpBinding的支持, 在Socket通信中通过HTTP检索策略文件, HTTP请求中的ClientHttp和BrowserHttp
    稳扎稳打 Silverlight 4.0 系列文章索引
    稳扎稳打Silverlight(54) 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
    返璞归真 asp.net mvc (8) asp.net mvc 3.0 新特性之 Model
  • 原文地址:https://www.cnblogs.com/smallSevens/p/7550001.html
Copyright © 2011-2022 走看看