Java中String的理解
Posted zafkiel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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()总是会在堆上开辟新的内存,但该块内存存储的字符串信息会先去常量池查查找,如果常量池有,则直接存下常量池的字符串的引用;如果没有则在堆上保存字符串信息。
如下图:
这里具体可以参考这篇文章:
深入理解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的一些思考和理解暂时先写到这里,以后如果有新思考会更新到这篇。
以上是关于Java中String的理解的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常(代码片段
Failed to convert property value of type ‘java.lang.String‘ to required type ‘int‘ for property(代码片段