Java中String类的一些知识

Java中String为什么要设计成final呢?
首先我们来写一个测试类:

package someTest;

public class String_test {
    public static String appendStr(String s) {
        s+="bbb";
        return s;
    }
    public static StringBuilder appendSb(StringBuilder sb) {
        return sb.append("bbb");
    }
    public static void main(String[] args) {
        String string=new String("aaa");
        String nString=appendStr(string);
        System.out.println("nString is:"+nString.toString());
        System.out.println("string is:"+string.toString());
        
        StringBuilder sBuilder=new StringBuilder("aaa");
        StringBuilder nStringBuilder=appendSb(sBuilder);
        System.out.println("nStringBuilder is:"+nStringBuilder.toString());
        System.out.println("sBuilder is:"+sBuilder.toString());
        
    }

}

我们来看看输出的结果:

nString is:aaabbb
string is:aaa
nStringBuilder is:aaabbb
sBuilder is:aaabbb

以上我们会发现String类区别于StringBuilder的一些不同点。
从中我们可以体会到String不可变的安全性


下面我们来看个比较严重的问题:
老规矩,上一段代码:

package com.cqu.someTest1;

import java.util.HashSet;

public class StringBuilder_test {

    public static void main(String[] args) {
        HashSet<StringBuilder> hSet=new HashSet<StringBuilder>();
        StringBuilder sb1=new StringBuilder("aaa");
        StringBuilder sb2=new StringBuilder("aaabbb");
        hSet.add(sb1);
        hSet.add(sb2);
        
        StringBuilder sb3=sb1;
        sb3.append("bbb");
        System.out.println(hSet);
    }
}

输出结果就是:

[aaabbb, aaabbb]

能看出什么问题吗,首先,StringBuilder型变量sb1和sb2分别指向堆内存当中的"aaa"和"aaabbb",将它们都插入到HashSet当中,到这里都没有问题。可之后sb3也指向了sb1的地址,StringBuilder没有不可变性的保护,sb3修改了"aaa",那么sb1也跟着就被篡改了。导致HashSet当中出现了两个"aaabbb",这很明显就违背了hashset键值的唯一性。


其次让我们来看看Java核心卷当中的一句话:

将方法或类声明为final主要目的是:确保它们不会再子类中改变语义。String类是final类,这意味着不允许任何人定义String的子类。换言之,如果有一个String的引用,它引用的一定是一个String对象,而不可能是其他类的对象。

另外,让我们来看看另外一段直观的解释:

1、线程安全。基本类型传值对象传引用,记住这一点。既然传引用,两个变量就有可能指向同一个String。而在String可变情况下,我要是通过一个变量来更改String,那么另一个变量取到的String也就变了!为什么?因为两个变量指向同个String。试想在多线程里,这会是多么可怕的一件事情:一个线程正在处理一个String,发现自己处理的String竟然变了。惊了?!shenmegui?!而且,因为多线程由CPU调度的关系,你难以确定到底这个可变的String会变成shenmegui。啥?你说封装在线程安全的类里?直接让他不可变多省事。
2、小明写了个方法:
String method(String origin){
origin += origin.substring(2);
return origin;}
然后他将同个字符串分别传入两次并打印:
Shenmeguienmegui
Shenmeguienmeguienmeguienmegui
小明惊了?!随即他发现,因为String是可变的,而第一次调用就已经改变了原来的字符串。所以……
String method(String origin){
String result = origin.clone();
result += result.substring(2);
return result;}
一边骂着Moon的工程师干嘛不让字符串不可变,小明终于得到了他要的输出:
Shenmeguienmegui
Shenmeguienmegui
幸好这个世界的Sun公司让String不可变,感谢Sun机智的工程师帮我们省了很多事。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容