String代表的是字符串常量,他们的值在创建后不能更改。字符串缓冲区支持可变的字符串。因为String对象是不可变的,所以可以共享。
源码分析:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
//缓存字符串的哈希码
private int hash; // Default to 0
String类继承了序列化,所以String类是可以被序列化的,另外,他的底层组成其实是个char 类型的数组,并且是final 类型的,这也进一步解释了为什么String的值一旦创建了之后是不能被修改的,String类中所有方法返回的都是一个新的String对象
// 也就是说
String str = "ABCD"; // 定义一个字符串对象,其实等价于:
char[] cr = new char[]{'A','B','C','D'};
String类中每一个看起来会修改String值得方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串对象.
String str = “hello word” //直接引用常量区
String str = new String(“hello world”) //在堆内存创建对象
在字符串中,如果采用直接赋值的方式(String str=“123”)进行对象的实例化,则会将匿名对象“123”放入对象池,每当下一次对不同的对象进行直接赋值的时候会直接利用池中原有的匿名对象.
总结:两种实例化方法的区别
1)直接赋值:只开辟一块堆内存空间,并且会自动入池,不会产生垃圾
2)构造方法:会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收,而且不能够自动入池,需要通过public String intern();方法进行手工入池。
==在对字符串比较的时候,对比的是内存地址,而equals比较的是字符串内容,在开发的过程中,equals()通过接受参数,可以避免空指向。
String str = null;
if(str.equals("hello")){//此时会出现空指向异常
...
}
if("hello".equals(str)){//此时equals会处理null值,可以避免空指向异常
...
}
string类对象一旦声明则不可改变,改变的只是地址,原来的字符串还是存在的,并且产生垃圾
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String str): 比较字符串的内容是否相同,忽略大小写
boolean startsWith(String str): 判断字符串对象是否以指定的str开头
boolean endsWith(String str): 判断字符串对象是否以指定的str结尾
boolean contains(CharSequence s): 判断字符串包含指定的字符值序列
@Test
public void test(){
String str1 = "abc";
String str2 = new String("abc");
String str3 = "ABC";
//以下全部为true
System.out.println(str1.equals(str2));
System.out.println(str1.equalsIgnoreCase(str3));
System.out.println(str1.startsWith("ab"));
System.out.println(str1.endsWith("bc"));
System.out.println(str1.contains("abc"));
}
int length():获取字符串的长度,其实也就是字符个数
char charAt(int index):获取指定索引处的字符
int indexOf(String str):获取str在字符串对象中第一次出现的索引
String substring(int start):从start开始截取字符串
String substring(int start,int end):从start开始,到end结束截取字符串。包括start,不包括end
@Test
public void test(){
String str = "abcd";
System.out.println(str.length()); //4
System.out.println(str.charAt(0)); //a
System.out.println(str.indexOf("a")); //0
System.out.println(str.substring(2)); //cd
System.out.println(str.substring(1,3)); //bc
}
char[] toCharArray():把字符串转换为字符数组
String toLowerCase():把字符串转换为小写字符串
String toUpperCase():把字符串转换为大写字符串
@Test
public void test(){
String str = "AbCdEf";
char[] chars = str.toCharArray();
for (char o : chars) {
System.out.print(o);
} //AbCdEf
System.out.println();
System.out.println(str.toLowerCase()); //abcdef
System.out.println(str.toUpperCase()); //ABCDEF
}
String trim():去除字符串两端空格
String[] split(String str):按照指定符号分割字符串
@Test
public void test5(){
String str = " A bCdEf "; //A bCdEf
System.out.println(str.trim());
String str2 = "a/b/nh/c";
String[] strs = str2.split("/");
for (String o : strs) {
System.out.print(o+" "); //a b nh c
}
}
Strings are constant; their values cannot be changed after they are created
//String 是个常量,从一出生就注定不可变。
因为String太过常用,JAVA类库的设计者在实现时做了个小小的变化,即采用了享元模式,每当生成一个新内容的字符串时,他们都被添加到一个共享池中,当第二次再次生成同样内容的字符串实例时, 就共享此对象,而不是创建一个新对象,但是这样的做法仅仅适合于通过=符号进行的初始化。
不可变对象不能被写,所以不可变对象自然是线程安全的
,因为不可变对象不能更改,它们可以在多个线程之间自由共享。后set包含了重复值。
不可变对象不能被写,所以不可变对象自然是线程安全的
,因为不可变对象不能更改,它们可以在多个线程之间自由共享。