zoukankan      html  css  js  c++  java
  • 不可变String


    1,什么是不可变String?

               String对象是不可变的。当试图修改String值的时候,实际上都是创建一个全新的String对象,该对象包含修改后字符串的值,而最初的对象则没有发生改变。

    package yfy;
    public class Test {
        public static void main(String[] args) {
            String a = "aa";
            String b = a;
            System.out.println(b);
            System.out.println(a==b);
            b = "cc";
            System.out.println(a);
            System.out.println(b);
            System.out.println(a==b);
        }
    }
    结果:
    a
    true
    a
    c
    false

    分析:开始引用a和b都指向堆中的对象“aa”;试图修改b引用所指对象“aa”时,实际上是新创建一个对象,然后把cc的地址给引用b,而引用变量a的值一直没有改变。

    image

    image

    public class TestString {
        static String upcase(String s){
            return s.toUpperCase();
        }
        public static void main(String[] args) {
            String s1 = "bbc";
            String s2 = upcase(s1);
            System.out.println(s1);
        }
    }
    结果:bbc

    分析:java中只有值传递,没有引用传递,这里有两种情况,一种是传对象,一种是传基础类型,传对象其实是传对象的引用,也就是传递的是对象的地址。基础类型传递的时候,直接把内存里面真正的值传递过去,而在对象传递的时候,是把对象的引用传递过去。上面的程序,s1作为参数传递的时候,其实是传递引用的一份拷贝。

    image

    image

    再总结一番:当s1作为实参传递给形参s的时候,其实是把s1所指对象的内容复制给s,s进行操作后得到一个最终结果,s2则指向这个结果。

    public static void main(String[] args) {
            String s= "s";
            String s2= "s";
            String s3= new String("s");
            String s4= new String("s");
            System.out.println(s==s2);
            System.out.println(s3==s2);
            System.out.println(s3==s4);
        }

    ==比较的是两个对象的地址,其实由上面的a,b指向同一对象知道,s==s2,而new String呢,不会理你堆中是不是有同样的"s"对象,每new一次,都重新创建一个,所以s3,s4,s2是不会==的。


    2,为什么String对象是不可变的?

    1,字符串常量池的需要。

           只有当字符串是不可变的,字符串池才有可能实现。字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。假若字符串对象允许改变,那么将会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象. 严格来说,这种常量池的思想,是一种优化手段.

                   String s1= "ab" + "cd";
                   String s2= "abc" + "d";

    s1和s2其实指向同一个对内存。

    2,如果字符串是可变的,会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。

    3,因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。

    4,类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。

    5,因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

    部分内容来自网络http://blog.csdn.net/iaiti/article/details/39180897

  • 相关阅读:
    [BJWC2011]最小三角形
    用于监视Linux上的内存使用情况的Bash脚本
    使用ps、top、ps_mem命令找出Linux中的最大内存消耗过程
    无法开机 如果您的手机黑屏无法开机,可以按照以下方式操作尝试: 如果是,使用原装充电器或使用弱电流方式充电(例如使用电脑USB接口充电)充电15-30分钟后尝试重新开机;注意:电量过低引起的无法开机,刚插入充电器时可能不亮屏但呼吸灯闪烁状态。
    Centos7 cache/buff过高处理方法
    上,打开SSH服务的配置文件:/etc/ssh/sshd_config 加上如下两行: ClientAliveInterval 120 ClientAliveCountMax 720 第一行,表示每隔120秒向客户端
    inux软件安装管理之——dpkg与apt-*详解
    在虚拟机中安装 Ubuntu
    一看就懂的 安装完ubuntu 18.04后要做的事情和使用教程
    一、apt的简介
  • 原文地址:https://www.cnblogs.com/yefengyu/p/4809909.html
Copyright © 2011-2022 走看看