首页IT科技string java基本数据类型(Java基础类String学习分析)

string java基本数据类型(Java基础类String学习分析)

时间2025-09-16 23:15:27分类IT科技浏览7164
导读:1 String不可变性 String类被声明为 final,因此它不可被继承。 内部使用char数组存储数据,该数组被声明为final,这意味着value数组初始化之后就不能再指向其它数组。 String内部没有改变value数组的方法 String类中所有修改...

1 String不可变性

String类被声明为 final                ,因此它不可被继承                 。 内部使用char数组存储数据                         ,该数组被声明为final        ,这意味着value数组初始化之后就不能再指向其它数组                        。 String内部没有改变value数组的方法 String类中所有修改String值的方法        ,如果内容没有改变                         ,则返回原来的String对象引用                 ,如果改变了        ,创建了一个全新的String对象                        ,包含修改后的字符串内容                 ,最初的String对象没有任何改变        。(目的:节约存储空间                、避免额外的开销) //String的类声明以及value字段代码: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; //字符数组存储String的内容 /** Cache the hash code for the string */ private int hash; // Default to 0 }

不可变的验证分析:

public class Immutable { public static String upcase(String s) { return s.toUpperCase(); } public static void main(String[] args) { String q = "howdy"; System.out.println(q); // howdy String qq = upcase(q); System.out.println(qq); // HOWDY System.out.println(q); // howdy } } /* 输出: howdy HOWDY howdy *///:~ 当把q传给upcase0方法时,实际传递的是引用的一个拷贝                 。 upcase0方法中                        ,传入引用s                         ,只有upcase0运行的时候,局部引用s才存在                         。一旦upcase0运行结束                ,s就消失        。upcaseO的返回值是最终结果的引用        。 综上                         ,upcase()返回的引用已经指向了一个新的对象        ,而原本的q则还在原地                         。

延伸结论:

String对象作为方法的参数时                ,都会复制一份引用                         ,参数传递是引用的拷贝

2 不可变的好处

1. 可以缓存 hash 值 String的hash值经常被使用        ,例如String用做HashMap的key                。不可变的特性可以使得hash值也不可变        ,因此只需要进行一次计算        。

2. String Pool 的需要 如果一个String对象已经被创建过了                         ,那么就会从 String Pool 中取得引用                         。只有String是不可变的                 ,才可能使用 String Pool                。

3. 线程安全 String不可变性天生具备线程安全        ,可以在多个线程中安全地使用。

3 String+和StringBuilder效率差异

String使用“+                ”表示字符串拼接

先说结论:

“+                         ”操作                        ,javac编译器会自动优化为StringBuilder.append() 调用                         。 StringBuilder要比“+        ”操作高效 涉及循环追加的                 ,手动创建StringBuilder对象操作比“+        ”操作编译器优化,更高效

验证:

public class StringBuilderTest { public static void main(String[] args) { String s1 = "ABC"; String s2 = "123"; String result = s1+s2; System.out.println(result); } }

编译并查看字节码:javap -verbose StringBuilderTest.class

执行过程:

调用了2次append()方法                        ,最后调用StringBuilder.toString()返回最终结果

为什么StringBuilder要比+高效?

+操作                         ,按照:每次追加都创建新的String对象,把字符加入value数组中                        。这里产生一次对象创建操作                ,以及对应的垃圾回收 StringBuilder的底层数组value也是用到了char[]                         ,但它没有声明为final        ,故它可变                ,所以追加内容时不用创建新的数组                         ,而是直接修改value StringBuilder比+省去String对象创建以及垃圾回收的开销        ,因此效率更高。

源码追溯:

//StringBuilder.append() @Override public StringBuilder append(char c) { super.append(c); return this; } // 父类 AbstractStringBuilder.append() @Override public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; } //AbstractStringBuilder value 字段 abstract class AbstractStringBuilder implements Appendable, CharSequence { //The value is used for character storage. char[] value; // 没有声明为final        ,因此value可变 }

手动实现StringBuilder对象操作比编译器自行优化                         ,更高效

通过字节码分析可知(我这里省去了                 ,可以自己实现验证):循环部分的代码更简短                         、更简单        ,而且它只生成了一个StringBuilder对象                 。 显式地创建StringBuilder还允许你预先为其指定大小                        。如果你已经知道最终的字符串大概有多长                        ,那预先指定StringBuilder的大小可以避免多次重新分配缓冲        。 当你为一个类编写toString方法时                 ,如果字符串操作比较简单,那就可以信赖编译 器                        ,它会为你合理地构造最终的字符串结果                 。但是                         ,如果你要在toString0方法中使用循环,那 么最好自己创建一个StringBuilder对象来实现                         。

4 String, StringBuffer and StringBuilder

可变性

String 不可变 StringBuffer和StringBuilder可变

线程安全

String不可变                ,因此是线程安全的 StringBuilder 不是线程安全的 StringBuffer 是线程安全的                         ,内部使用synchronized进行同步

效率

如果要操作少量的数据用String 单线程环境且字符串缓冲区涉及大量数据 StringBuilder 多线程环境且字符串缓冲区涉及大量数据 StringBuffer

5 String与JVM内存管理

一        、引入字符串常量池

Javac编译后        ,字节码文件中有一块区域:常量池                ,存储了包括类中声明的字符串常量值等字面量 运行时                         ,JVM开辟实际内存空间:字符串常量值写入了字符串常量池        ,属于方法区的一部分        。

案例1

String s1 = "win"; String s2 = "win"; System.out.println(s1==s2); //输出结果:true //引用 s1 s2 的值等于win在字符串常量池的地址值

结论:

引用 s1 s2 的值等于win在字符串常量池的地址值

分析字节码的执行过程:

案例2

public class StringPool { public static void main(String[] args) { String s3 = new String("win"); String s4 = new String("win"); System.out.println(s3==s4);//false } }

结论:

通过new操作符创建的字符串对象不指向字符串池中的任何对象

        。

字节码分析:

综上:

public class StringPool { public static void main(String[] args) { String s1 = "win"; String s2 = "win"; String s3 = new String("win"); String s4 = new String("win"); System.out.println(s1==s2);//true System.out.println(s1==s3);//false System.out.println(s3==s4);//false } }

6 String api方法

从这个表中可以看出        ,当需要改变字符串的内容时                         ,String类的方法都会返回一个新的String对象                         。同时                 ,如果内容没有发生改变        ,String的方法只是返回指向原对象的引用而已                。这可以节约存储空间以及避免额外的开销        。

声明:本站所有文章                        ,如无特殊说明或标注                 ,均为本站原创发布                         。任何个人或组织,在未征得本站同意时                        ,禁止复制        、盗用                         、采集                 、发布本站内容到任何网站        、书籍等各类媒体平台                。如若本站内容侵犯了原著者的合法权益                         ,可联系我们进行处理。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
seo做网站(掌握SEO的基本步骤,让你的网站跻身顶尖!) 免费的wordpress主题(电脑学习网免费wordpress主题破解版本Zibll子比主题V5.7最新版完美破解-电脑学习网)