概念介绍
String类是被final所修饰的,因此String类对象不可变,也不可继承。这里要注意一个误区,字符串对象不可变,但字符串变量所指的值是可变的,即引用地址可变。String变量存储的是对String对象的引用,String对象里存储的才是字符串的值. 例子如下:String str = "abc"; //str是个对象引用,一个字符串变量
System.out.println(str); //输出abc
str = "abcde"; //str这个字符串变量所指的值可变
System.out.println(str); //输出abcde
当给
str第二次赋值的时候,对象 "abc" 并没有被销毁,仍存放在常量池中(String自带),只是让str指向了 "abcde" 的内存地址,而字符串对象 "abcde" 是新生成的,即str第二次赋值时并不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。记住,对String对象的任何改变都不影响到原对象,相关的任何改变的操作都会生成新的对象。
String的两种赋值方式
区分【String str="HW"】和【String str=new String("HW") 】
1. 字面量赋值方式 eg:String str = "Hello";
该种直接赋值的方法,JVM会去字符串常量池(String对象不可变)中寻找是否有equals("Hello")的String对象,如果有,就把该对象在字符串常量池中"Hello"的引用复制给字符串变量str,如若没有,就在堆中新建一个对象,同时把引用驻留在字符串常量池中,再把引用赋给字符串变量str。用该方法创建字符串时,无论创建多少次,只要字符串的值(内容)相同,那么它们所指向的都是堆中的同一个对象。
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上
2. new关键字创建新对象 eg:String str = new String("Hello");
利用new来创建字符串时,无论字符串常量池中是否有与当前值相同的对象引用,都会在堆中新开辟一块内存,创建一个新的对象。
注意:对字符串进行拼接操作,即做"+"运算的时候,分2种情况:
1、表达式右边是纯字符串常量,那么存放在常量池里面。eg:String str = "Hello" + "World";
2、表达式右边如果存在字符串引用,也就是字符串对象的句柄,那么就存放在堆里面。eg:String str = str1 + str2;
总结:常量池是方法区的一部分,而方法区是线程共享的,所以常量池也是线程共享的,且它是线程安全的,它让有相同值的引用指向同一个位置,如果引用值变化了,但是常量池中没有新的值,那么就会新建一个常量结果来交给新的引用,对于同一个对象,new出来的字符串存放在堆中,而直接赋值给变量的字符串存放在常量池里。
String拼接
字符串比较: 区分 "==" 和 "equals"
"==":比较引用变量的地址,即两个对象是否引用同一地址的内容,会检测是否指向同一个对象。
"equals":比较对象的内容,即两个对象内容上是否相同
字符串用这两种比较方式都是可行的,具体看想要比较什么,总体来看,"=="稍微强大些,因为它既要求内容相同,也要求引用对象相同.
连接字符串
public class StringDemo {
public static void main(String args[]) {
String string1 = "菜鸟教程网址:";
System.out.println("1、" + string1 + "www.runoob.com");
}
}
输出
"Hello, runoob!"
public class StringDemo {
public static void main(String args[]) {
String string1 = "菜鸟教程网址:";
System.out.println("我的名字是 ".concat("Runoob");)
}
}
输出:
我的名字是 Runoob
字符串拼接五种方法
- 使用 +
- 使用 concat
- 使用 StringBuilder
- 使用 StringBuffer
- 使用 StringUtils.join
效率(用时长短): StringBuilder < StringBuffer < concat < + < StringUtils.join
+是Java提供的一个语法糖,而使用+拼接的字符串,它将String转成了StringBuilder后,再使用StringBuilder.append进行处理。如果不是在循环体中进行字符串拼接的话,直接使用+就好了。- concat方法,其实是new了一个新的String
- StringUtils.join也是通过StringBuilder来实现的
- StringBuffer在StringBuilder的基础上,做了同步处理,所以在耗时上会相对多一些。
- 如果在并发场景中进行字符串拼接的话,要使用StringBuffer来替代StringBuilder。因为StringBuilder是线程不安全的,而StringBuffer是线程安全的
- 由于String是Java中一个不可变的类,所以他一旦被实例化就无法被修改,因此所有的所谓字符串拼接,都是重新生成了一个新的字符串。
总结:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用于多线程下在字符缓冲区进行大量操作的情况
常用方法
char charAt(int index)
返回指定索引处的 char 值。
int compareTo(String anotherString)
按字典顺序比较两个字符串。
int compareToIgnoreCase(String str)
按字典顺序比较两个字符串,不考虑大小写。
String concat(String str)
将指定字符串连接到此字符串的结尾。
boolean endsWith(String suffix)
测试此字符串是否以指定的后缀结束。
boolean equals(Object anObject)
将此字符串与指定的对象比较。
boolean equalsIgnoreCase(String anotherString)
将此 String 与另一个 String 比较,不考虑大小写。
int indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(int ch)
返回指定字符在此字符串中最后一次出现处的索引。
int length()
返回此字符串的长度。
String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
String toLowerCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
String toString()
返回此对象本身(它已经是一个字符串!)。
String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
String toUpperCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
isEmpty()
判断字符串是否为空。