JAVA没有内置的字符串类型,标准的java类库中提供了一个预定义类,很自然的叫做String。每个用双引号括起来的字符串都是String类的实例。
三者的区别。
## String
一个String实际上是一个char数组。
String类是不可改变类,String类每次的改变都会形成一个新的实例,旧的实例如果没有被复用的化,就是在等待回收的过程。
String类是引用类型,存放在内存堆中,有“不可变”的特性(驻留机制),但是在做字符串拼接的时,每次都会创建一个新的对象,也就是每次都要去申请内存空间,因为做大量字符串拼接的时候性能很差,只适合做少量的字符串拼接。
### new String(“string”)和 “string”的区别?
## StringBuild
StringBuild是非线程安全的字符序列可变的字符串。
在String的基础上对StringBuilder做了有话,不会每次都去申请内存,二十一下子就申请一大块内存,做大量的字符串拼接性能非常高。
## StringBuffer
StringBuffer是线程安全的字符序列可变的字符串。
提供方法
## String
String.join("","S","t","r","i","n","g");
// 输出结果 String
//String类重写了equals方法,比较的是组成字符串的每一个字符是否相同,如果都相同则返回true,否则返回false。
String.equals(Object anObject)
contentEquals(StringBuffer sb)
//与equals最大的差别是,equals方法只有在另一个对象是String的情况下才可能返回true,而contentEquals只要求另一个对象是CharSequence或其子类的对象。
contentEquals(CharSequence cs);
equalsIgnoreCase(String anotherString)
regionMatches(int toffset, String other, int ooffset, int len)
regionMatches(boolean ignoreCase , int toffset, String other, int ooffset, int len)
hashCode()
源码实现
## Stirng
public int hasCode(){
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;
}
//
s数组即源码中的val数组,也是构成字符串的字符数组。这里有个数字31,为什么选择31作为乘积因子,而且没有用一个常量来生命?主要原因有两个:
1,31是一个不大不小的质数,是作为hashCode乘子的优选质数之一。
2,31可以被JVM有话,31 * i = (i << 5) - i。因为移位运算比乘法运行更快更省性能。
public char charAt(int index){
if((index < 0) || (index >= value.length)){
Throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
一个字符串都是由字符数组组成,这个方法是通过传入的索引(数组下标),返回指定索引的单个字符。
···
public int compareTo(String anotherString){
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1,len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while(k < lim){
char c1 = v1[k];
char c2 = v2[k];
if(c1 != c2){
return c1 - c2;
}
k++;
}
return len1-len2;
}
···
该方法是按字母顺序比较两个字符串,是基础字符串每个字符的Unicode值。当两个字符串某个为之的字符串不同时,返回的是这一位置的字符串Unicode值差,当两个字符串都相同时,返回两个字符串长度之差。
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
CompareToIgnoreCase()方法在CompareTo方法的基础上忽略了大小写,我们知道大写字母比小写字母的Unicode值小32,底层实现是先都转换成大写比较,然后都转换成小写比较。