创建字符串的方式有很多,String 类有 11 种构造方法,这些方法提供不同的参数来初始化字符串:
1、直接赋值,String a = "abc";
2、利用字符数组,char[] b = {'a', 'b','c'};String c = new String(b);
还有很多,比如利用StringBuffer、StringBuilder类。
注意:String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了.如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。
注意: String a = “abc”;a = a + “def”;这里字符串a的值改变了,但是内部的操作是首先把串池中的abc地址赋给a,第二句是把abcdef的地址赋给a,之前的字符串对象仍然存在,相当于垃圾。
同样的道理String s1 = "abc"; s1 = "abcd";
表面上s1的值改变了,只是s1在堆内的指向改变了,s1本来指向串池内的"abc",执行第二句后s1指向了"abcd",原来的"abc"是没有改变的,变成了垃圾。
public static void main(String[] args) {
String a = "abc"; // 常量池,a指向常量池中“abc”的地址
char[] b = {'a', 'b','c'}; // 堆内存
System.out.println(a);
System.out.println(b);
String c = new String(b); // 堆内存,c指向堆内存中String对象的地址,改对象地址内存储的是常量池中“abc”的地址
System.out.println(c);
System.out.println(a == c); // a和c存储的地址不同,因此返回false
System.out.println(a.equals(c)); // String类重写了equals方法,比较的是两个对象的内容,a和c的内容都是“abc”因此返回true
System.out.println(a.concat(c));//连接两个字符串
String s1 = "a";
String s2 = s1+"b"; // s1对象和常量池中的“b”做运算
String s3 = "a" +"b"; // 编译对字符串常量直接相加的表达式进行优化,常量池中生成“ab”,s3指向“ab”
String s4 = "ab"; // s3指向“ab”
System.out.println(s2 == s3);//false
System.out.println(s2 == s4);//false
System.out.println(s3 == s4);//true
}
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类
StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
public static void main(String[] args) {
StringBuilder d = new StringBuilder("abc");
System.out.println(d);
d.append(b); // 可以改变字符串
System.out.println(d);
StringBuffer e = new StringBuffer("abc");
e.append(b); // 可以改变字符串
System.out.println(e);
}
String类的hashCode()和equals()方法:
hashCode方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
为什么要这样计算hashCode?
1、字符串的哈希值被计算并且赋值给hash字段,之后再调用hashCode方法便可以直接取hash字段返回。
2、以31为权,每一位为字符的ASCII值进行运算,用自然溢出来等效取模。
哈希计算公式可以计为s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
3、31 是一个奇质数。一方面可以产生更分散的散列,即不同字符串 hash 值也一般不同,所以在选择系数的时候要选择尽量长的并且让乘法结果尽量不要溢出的系数,如果计算出来的hash地址越大,所谓的「冲突」就越少,查找起来效率也会提高。但是也不能过大,在 java 乘法中如果数字相乘过大会导致溢出的问题,从而导致数据的丢失。另一个方面主要是计算效率比较高,31 * i=32 * i - i=(i << 5) - i,这种位移与减法结合的计算相比一般的乘法运算快很多。
equals方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
equals方法依次比较两个字符串的每个字符是否相等。
String类的常见方法
1、字符串与字符数组的转换
public static void main(String[] args) {
String string = "abcdef";
char[] c = string.toCharArray();
for (int i = 0; i < c.length; i++) {
System.out.println(c[i]);
}
}
结果:
a
b
c
d
e
f
2、字符串取指定位置的字符
public static void main(String[] args) {
String string = "abcdef";
System.out.println(string.charAt(4));
}
结果:
e
3、字符串去空格
public static void main(String[] args) {
String string = " abc def ";
System.out.println(string.trim());
System.out.println(string.strip());
}
结果:
abc def
abc def
4、字符串截取
public static void main(String[] args) {
String string = "abcdef";
System.out.println(string.substring(4));//从第5个开始截取
System.out.println(string.substring(2, 5));//截取第3-5个
}
结果:
ef
cde
5、字符串拆分
public static void main(String[] args) {
String string = "abc.def";
String[] spilt = string.split("\\.");
for (int i = 0; i < spilt.length; i++) {
System.out.println(spilt[i]);
}
}
结果:
abc
def
6、字符串大小写转换
public static void main(String[] args) {
String string = "abCdef";
String string2 = string.toUpperCase();
System.out.println(string2);
String string3 = string.toLowerCase();
System.out.println(string3);
}
结果:
ABCDEF
abcdef