Java中String的理解

  • 格式:pdf
  • 大小:116.72 KB
  • 文档页数:2

Java中String的理解

Java中String的理解

最近在读String的源码,看了些String的⽂章,⾃⼰对String作了下总结记录下来。

1.String为什么是不可变的?

String是final类,不可继承,其⽅法也不可被覆盖,避免从⼦类操纵⽗类属性;String的值保存在private final char[]数组中,本质是⼀个字符数组,私有则外部不可访问和修

改,final引⽤则引⽤(或说引⽤的值)不变。引⽤可以简单地认为是堆上对象的⾸地址。String内部的private int hash,缓存hash值,hashCode和equals⽤来⽐较对象相等,缓

存hash可以减少运算时间提⾼效率。但是,String的值char[]可以通过反射改变。String不可变是出于安全和使⽤效率考虑的。

2.String的split,substring,replace,replaceAll等⽅法有哪些注意点?

charAt,toLowerCase,toUpperCase,trim,toCharArray等常⽤⽅法并没有太多注意点。

split(String regex,int limit):regex,切⽚的正则;limit,切⽚数。

split(String regex):regex,切⽚的正则。从这⾥可以看出切⽚是使⽤正则来切⽚的,⽽且要注意的是,尾部切⽚得到的空字符串""(注意没有空格)是不会出现的结果的字符串数组

中的。

思考:

String s=“,1,2,,3,,,”;

String[] arr=s.split(",");

arr的值是什么?

结果是{"",“1”,“2”,“”,“3”}。如果制定切⽚数limit则会按切⽚数切⽚。

substring(int beginIndex,int endInx):beginIndex是包含的,end不包含。

replace():有两个⽅法,接收char替换,接收字符序列(字符串)替换。

replaceAll(String regex,String replacement):⽤replacement替换所有的符合regex正则的⼦串。

3.String,StringBuilder,StringBuffer

对String的修改总是返回新的String,原String不变。

StringBuiler⾮线程安全,StringBuffer线程安全。StringBuffer认为线程安全是其⽅法使⽤synchronized同步,同时也会承担其带来的开销。

对⼤量修改字符串的操作推荐使⽤StringBuilder。

4.toString()⽅法,String与“+”操作符,对象与Object的toString⽅法

所有类都间接继承来⾃Object,所有对象实例都是Objcet的实例,如果不重写,则继承其toString(),hashCode(),equals()⽅法。打印⽇志,系统输出等带有“显⽰”含义的对实例

的表⽰都是调⽤其toString()⽅法。默认的toString⽅法时Class Name+"@"+⼗六进制的hashCode值。String的“+”可以看做所谓的运算符重载,但是Java没有运算符重载。String

的“+”,和数值的“+”有所不同,⼀般情况String的“+"就是join操作把字符或字符串拼接。

看下⾯例⼦:

System.out.println(s+5+6);

System.out.println(5+6+s);

System.out.println(5+s+6);

System.out.println(s+(5+6));```

思考输出结果。
结果是:


hello56


11hello


5hello6


hello11


应避免此类写法或者加上括号指定运算顺序。

##5.String在JVM的存储


JVM在创建我们常见的字符串常量,⽐如String s=“abcd”,和字符串对象,⽐如String s=new String("abcd")时⾏为有所区别。


字符串常量:⽐如String s="abcd",创建字符串常量时,JVM会⾸先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引⽤。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。常量池中


字符串对象:String s=new String(“abcd”);注意这⾥没有上⾯String s="abcd"的先决条件。在类加载时,常量池会创建“abcd”对象,指向代码时在堆上创建⼀个String对象,该String对象保存到常量池“abcd”对象的引⽤,s保存到堆上该String

创建字符串总是先去常量池找是否已有当前字符串对象,没有才去堆上分配,在堆上新分配的也不会加到常量池


思考:

```String s1="ABC";

String s2="ABC";

String s3=new String("ABC");

System.out.println(s1==s2);

System.out.println(s1==s3);```


输出结果是什么?


结果是:true


false


new String()总是会在堆上开辟新的内存,但该块内存存储的字符串信息会先去常量池查查找,如果常量池有,则直接存下常量池的字符串的引⽤;如果没有则在堆上保存字符串信息。

如下图:![](https://img2018.cnblogs.com/blog/1476330/201903/1476330-20190313114258718-1875513481.jpg)

这⾥具体可以参考这篇⽂章:[深⼊理解Java中的String](https://www.cnblogs.com/xiaoxi/p/6036701.html)

##6.String,对象,集合的判空和判null


对于某个对象判null,直接s==null即可。在⽇常学习⼯作中,很多情况都是对空字符串,空集合的判断。


集合的判空不能⽤==null,应该⽤⼯具类,其内部实现⼀般是判null或元素数为0则为空集合。


对于⼀个指定为String类型的引⽤s,如果判断空字符串?


思考:


String s=null;


System.out.println(s);


输出:null


思考:


System.out.println("".equals." ");


输出:false


对于字符串的判空还是要借助⼯具类才能保证全⾯性。思路是:判null,trim去除头尾空格再判空,⽽且对于“null”本⾝这个字符串应该视为
是空字符串,在某些序列化结果和数据库返回结果,null会被直接传送返回,应该剔除这种情况。在⽇

对String的⼀些思考和理解暂时先写到这⾥,以后如果有新思考会更新到这篇。