string 类的介绍

String类介绍

一、String类介绍:

        String是一个引用数据类型默认为null;
        String 为final类型不可更改,不能被继承;
        基本类型与String结合都会转换为String类型;

二、String两种赋值方式:

1)直接赋值:String str = " ";

String str = "" 原理:
        在 JVM(虚拟机)中有一个字符串池,专门用来存储字符串。如果遇到 String a=”hello”时(注意没有 NEW,不是创建新串),系统在字符串池中寻找是否有 ”hello”,
        此时字符串池中没有”hello”,那么系统将此字符串存到字符串池中,然后将 ”hello”在字符串池中的地址返回 a。
        如果系统再遇到String b=”hello”,此时系统可以在字符串池中找到  “hello”。则会把地址返回b,此时 a与b 为相同。

 

2)使用new进行赋值:String str = new String (" ");

 

3) 两种赋值方式的区别:
            1、直接定义的String "a"是储存在常量存储区中的字符串常量池中;new String(“a”)是存储在中;
            2、常量池中相同的字符串只有一个,但是new String(),每new一个对象就会在堆中新建一个对象;
            3、String a = “a”在编译阶段就会在内存中创建;String a = new String(“a”);是在运行时才会在堆中创建对象;


 
 
  1. String a = "hello";
  2. String b = "hello";
  3. System.out.println(a == b ); //true a b 指向同一个值,地址相同
  4. System.out.println(a.equals(b)); //true a b 是同一个值,当然相等
  5. String a1 = new String ( "hello");
  6. String b1 = new String ( "hello");
  7. System.out.println(a1 == b1 ); //false 每次new都会创建一个新对象,a1 b1 地址不同
  8. System.out.println(a1 .equals(b1) ); //true

由此可以得出两种实例化方式的区别

      1)直接赋值(String str = "hello"):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。

      2)构造方法(String str=  new String("hello");):会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收

        在开发的过程中不会采用构造方法进行字符串的实例化。

4)常量池

字符串常量池在jdk1.6及之前在方法区中,但是在jdk1.7及以后就放在了堆中

编译阶段确定的字符串才会被放到字符串常量池中

分析下面创建几个对象:


 
 
  1. String s1 = "java";
  2. String s2 = "从0到1";
  3. String s3 = "java从0到1";
  4. String s4 = s1+s2;
  5. System.out.println(s3==s4);

s1和s2还有s4都会在字符串常量池中,这已经有三个对象了 。关键在于这行代码上String s3 = s1 + s2;

对于s3无法在编译阶段确定下来,所以无论最后的字符串是什么都不会存在字符串常量池中,那么存在哪呢?因为对象创建在堆中,而字符串常量池也在堆中,既然不在字符串常量池中那就是在字符串常量池之外的堆中了,而s3最终的字符串对象是“Java从0到1”,那么也就是说这个字符串在常量池之外的堆中,这是一个对象了,加上之前的三个,这里一共四个了,但是我们还要分析这个s3是怎么来的,是通过s1和s2相加得到的,因为这个s3最终是在常量池之外的堆中形成的,而s1和s2都是在常量池中,因此会将s1和s2拷贝一份到字符串常量池之外的堆中来形成s3,我们看下面的一张图来加深理解

堆内存复制s1,s2,这样的话要再加上两个对象,那一共就是创建6个对象了!

三、String源码解析:

Jdk1.7 的String源码如下: 


 
 
  1. public final class String
  2. implements java. io. Serializable, Comparable< String>, CharSequence {
  3. /** The value is used for character storage. */
  4. private final char value[];
  5. /** Cache the hash code for the string */
  6. private int hash; // Default to 0

由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装,除此之外还有一个hash成员变量,是该String对象的哈希值的缓存。
value这个变量是final的, 也就是说在String类内部,一旦这个值初始化了, 也不能被改变。所以可以认为String对象是不可变的了。

String s = new ("ABCabc"); 对应的内存模型为:

当我们调用a.replace('A', 'a')时, 方法内部创建了一个新的String对象,并把这个新的对象重新赋给了引用a;

因此结果为 aBCabc

Spring是否真的是不可变?

我们知道被final修饰的引用类型变量是引用的地址不可变,而不是引用的值不可变,因此我们能否改变value数组的值而使String改变???答案当然是可以的,反射可以搞定。

反射可以访问私有成员,因此我们可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。


 
 
  1. public static void testReflection() throws Exception {
  2. //创建字符串"Hello World", 并赋给引用s
  3. String s = "Hello World";
  4. System. out.println( "s = " + s); //Hello World
  5. //获取String类中的value字段
  6. Field valueFieldOfString = String.class.getDeclaredField( "value");
  7. //改变value属性的访问权限
  8. valueFieldOfString.setAccessible( true);
  9. //获取s对象上的value属性的值
  10. char[] value = ( char[]) valueFieldOfString. get(s);
  11. //改变value所引用的数组中的第5个字符
  12. value[ 5] = '_';
  13. System. out.println( "s = " + s); //Hello_World
  14. }

在这个过程中,s始终引用的同一个String对象,但是再反射前后,这个String对象发生了变化, 也就是说,通过反射是可以修改所谓的“不可变”对象的。但是一般我们不这么做。这个反射的实例还可以说明一个问题:如果一个对象,他组合的其他对象的状态是可以改变的,那么这个对象很可能不是不可变对象。例如一个Car对象,它组合了一个Wheel对象,虽然这个Wheel对象声明成了private final 的,但是这个Wheel对象内部的状态可以改变, 那么就不能很好的保证Car对象不可变。

四、String进行字符串拼接:

拼接原理:String是字符串常量的引用,String += String的本质是new了新的临时对象StringBuild,拼接后再把StringBuild.toString赋给原String。


        String s="a"+"b"+"c"+"d"; 实际只创建了一个对象  ,过程是new 了 一个临时的StringBuild,然后把"a"+"b"+"c"+"d"进行拼接,结果"abcd".toString 返回gei s;
        
        所有大量字符串拼接不要直接使用String,否则会生成大量临时对象,严重影响性能。 

五、String,StringBuffer, StringBuilder比较:

        
        1、String是字符串常量,StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变,而前者创建后内容不可变(String进行字符串拼接时创建新对象)。

        2、StringBuffer是线程安全的,而StringBuilder是非线程安全的。

        3.线程安全会带来额外的系统开销,所以StringBuilder的效率比StringBuffer高。如果对系统中的线程是否安全很掌握,
        可用StringBuffer,在线程不安全处加上关键字Synchronize。

        4.  StringBuffer 和 StringBuilder 要调用.toString方法在进行比较

  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">10</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/Bruce_Up">
                    <img src="https://profile.csdnimg.cn/D/2/1/3_bruce_up" class="avatar_pic" username="Bruce_Up">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/Bruce_Up" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">Bruce_Up</a></span>
                                            </div>
                    <div class="text"><span>发布了51 篇原创文章</span> · <span>获赞 27</span> · <span>访问量 2万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=Bruce_Up" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    </article>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值