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操作把字符或字符串拼接。

看下面例子:
String s=“hello”; 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指向常量池中的“abcd”对象,s的值简单理解为常量池中的“abcd”对象的地址。

字符串对象: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()总是会在堆上开辟新的内存,但该块内存存储的字符串信息会先去常量池查查找,如果常量池有,则直接存下常量池的字符串的引用;如果没有则在堆上保存字符串信息。
如下图:
1476330-20190313114258718-1875513481.jpg

这里具体可以参考这篇文章:
深入理解Java中的String

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会被直接传送返回,应该剔除这种情况。在日常学习工作中,判空,判null,判等这些
操作一定要特别注意。



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

转载于:https://www.cnblogs.com/Zafkiel/p/10522123.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值