String类进阶简单梳理
1、String类简单介绍
String类不是Java的8大基本数据类型,它是属于java.lang
包下的。
同时由于String类是有final关键字修饰的,所有它不能被继承,不能有子类。
String类的底层是char数组,也是final关键字修饰的,所以它不能被更改。
2、String类的存储原理
String类对象有个特殊的创建方式,也就是直接指定String类对象等于一个字符串,像这样:String str="HelloWorld"
。或者使用String类的构造方法,像这样String str=new String("HelloWorld")
。但是这两者在内存中有很大的区别。
-
直接等于字符串String str=“HelloWorld”
JVM中是先创建在常量池里创建了
"HelloWorld"
这个字符串,然后str存的就是这个字符串对象的地址,所以str实际上是这个字符串的引用。这个字符串只要被创建出来就不能被改变或者消失会一直存在。所以,如果另外一个字符串str2也直接等于
"HelloWorld"
,那么str和str2如果比较地址,那么他们两个是一样的(内容也一样)。String str="Hello,World"; String str2="Hello,World"; System.out.println(str == str2);//true
内存图:
只要某个字符串被创建,他们它就会一直存在,不会消失。所以拼接字符串的时候,拼接两个字符串实际上会在常量池中创建3个字符串
String str="Hello,World"+"->Java";//"Hello,World","->Java","Hello,World->Java"
内存图:
-
使用构造方法String str=new String(“HelloWorld”)
JVM中仍然是先在常量池中创建了字符串常量,然后new出来的String类型的对象存在堆中,然后栈中的str存的是刚刚new出来的String对象的内存地址。
所以,如果两个通过new String出来的String对象通过比较的地址的方式比较是不相等的。
String str1 = new String("HelloWorld"); String str2 = new String("HelloWorld"); System.out.println(str1 == str2);//false
内存图:
总结:直接等于字符串的方式新建出来的是字符串常量,无法被改变,并且即使创建了一样的字符串,那么依旧是相等的。如果通过new String的方法new出来的字符串变量是指向堆中的String类对象的,即使字符串内容相等,但是对象不相等。所以字符串比较内容尽量中equals()方法比较。
3、String类的构造方法
String(); //空字符串
String(byte[] bytes); //通过byte数组创建字符串
String(byte[] bytes, int offset, int length); //offset是数组的第几个开始,length是长度
String(char[] value); //通过char数组创建字符串
String(char[] value, int offset, int count); //offset是数组的第几个开始,length是长度
String(String original); //用String对象创建字符串
String(StringBuffer buffer); //用StringBuffer创建字符串
String(StringBuilder builder); //用StringBuilder创建字符串
4、String类的常用方法
char charAt(int index); //返回指定索引的char值
int compareTo(String anotherString); //比较两个字符串(通过ASCII码)
String concat(String str); //将str添加到该字符串末尾
boolean contains(CharSequence s); //判断该字符串是否包含字符串s
boolean endsWith(String suffix); //判断该字符串是否以suffix字符串结尾
boolean equals(Object anObject); //将两个字符串进行比较
byte[] getBytes(); //将该字符串转换为byte数组
int indexOf(String str); //返回第一次出现str字符串的索引
boolean isEmpty(); //判断该字符串是否为空
int lastIndexOf(String str); //返回最后一次出现str字符串的索引
int length(); //返回该字符串的长度
String replace(String oldString, String newString); //将该字符串中的oldString字符替换成newString字符
String[] split(String regex); //利用正则或者字符串来分割该字符串
boolean startsWith(String prefix); //判断该字符串是否以prefix字符串开始
String substring(int beginIndex, int endIndex);//截取字符串从beginIndex开始到endIndex结束,endIndex默认是结尾
char[] toCharArray(); //将该字符串转换为char数组
String toLowerCase(); //将字符串全部转换为小写
String toUpperCase(); //将字符串全部转换为大写
String trim(); //将前导或结尾的空字符串去掉
5、valueOf()方法
valueOf( )方法可以将所有的基本数据类型转换为字符串类型,在println( )的底层其实也就是调用了对象的valueOf( )方法
6、StringBuffer
如果通过String类来拼接字符串的话,每次拼接都会创建新的字符串对象到常量池里,很浪费内存空间,所以java.lang.StringBuffer
就是专门用来拼接字符串的,底层同样是char数组,但是没有final关键字修饰,所以它是可变的。默认的容量是16,可以通过构造方法来指定容量大小。底层是可扩容的,如果超过了大小就会自动扩容,同时是线程安全的,方法都有sychronized关键字修饰。
通过append( )方法来添加元素,每次添加都是到末尾,可以添加基本数据类型和Object类型等。执行append( )方法会调用String类的valueOf( )方法,然后valueOf( )方法又会调用类对象的toString方法,所以我们需要重写toString方法。
通过insert(int index,Object o)向指定位置插入元素。
7、StringBuilder
跟StringBuffer差不多,但是线程不安全,方法都没有sychronized关键字修饰。