1. String是如何实现的?它有哪些方法
- String类被final修饰,表明此类不能被继承,其中的方法也都是final类型;
- String类型实现了Serializable, Comparable, CharSequence接口;
- String类的值是通过char型数组存放,并且被private和final修饰,表明字符串一旦创建不能修改;
实现:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
//final修饰的char型数组存储字符串值
private final char value[];
//缓存字符串的hashcode
private int hash;
//....其他内容
}
方法:
1) 多构造方法
(1)String为参数的构造方法
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
(2)char[]为参数的构造方法
public String(char[] value) {
this.value = Arrays.copyOf(value,value.length);
}
(3)StringBuffer为参数的构造方法
public String(StringBuffer buffer) {
synchronized(buffer){
this.value = Arrays.copyOf(buffer.getValue(),buffer.length());
}
}
(4)StringBuilder为参数的构造方法
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(),builder.length());
}
2) equals()比较两个字符串相等
String类重写了Object类型中的equals()方法,比较的是内容
public boolean equals(Object anObject) {
//对象引用相同直接返回true
if(this == anObject){ //==对于引用数据类型比较引用地址
return true;
}
//判断需要对比的值是否是String类型,如果不是则直接返回false
if(anObject instanceof String){ //使用instanceof关键字判断是否属于String类型
String anotherString = (String)anObject;
int n = value.length;
//判断二者长度是否一致,不一致返回false
if(n == anotherString.value.length){
//把两个字符串都转换为char数组对比
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//循环对比两个字符串的每一个字符
while(n-- != 0){
//如果其中有一个不相等就返回false,否则继续对比
if(v1[i] != v2[i]){
return false;
}
i++;
}
return true;
}
}
return false;
}
补充:instanceof 使用
Object oString = "123";
Object oInt = 123;
System.out.println(oString instanceof String); //true
System.out.println(oInt instanceof String); //false
3) compareTo()比较两个字符串,返回-1,0,1
public int compareTo(String anotherString){
int len1 = value.length;
int len2 = anotherString.value.length;
//获取两个字符串长度最短的那个int值
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){
//如果字符不相等,就返回c1-c2,结果有-1,1
return c1 - c2;
}
k++;
}
return len1 - len2;
}
补充:与equals()的不同
- equals()可以接受Object类型参数,compareTo()只能接受String类型参数
- equals()返回类型是boolean,compareTo()返回值类型是int
4) 其他方法
indexOf();
lastIndexOf();
contains();
toLowerCase();
length();
trim();
replace(); //replace没有在原字符串上修改,而是另外创建了一个字符串
split();
join(); //把字符串数组转为字符串
2. String类为什么要用final修饰?
1) - 安全性:
因为字符串是不可变的,所以多线程是安全的,同一个字符串可以被多个线程共享
不必额外做同步操作;
String类被许多java类当作参数,如url,文件路径path等,如果可变就会产生安全隐患。
2) - 效率
字符串不变保证了hash码的唯一,可以放心的进行缓存;
只有字符串不变,字符串常量池才可以实现,
当创建一个String对象时,当此串值已存在于常量池中,就不会再创建新的对象,而是引用已存在的对象。
3. 字符串常量池?
JVM为了提高系能减小内存开销,在实例化字符串时用字符串常量池进行优化;
当创建字符串时,JVM会首先检查字符串常量池,如果该字符串已存在于池中,那么就直接返回池中的实例引用;
如果池中不存在,就会实例化该字符串并放到池中。
补充:new String("abc")创建了几个对象?
一个或两个
如果"abc"之前没使用过,就会创建两个对象,堆中创建一个,字符串常量池创建一个;
如果之前用过,只会在堆中创建一个。
4. 字符串拼接?
在循环内拼接字符串使用 += 会出现问题
String的 += 底层实际使用的是StringBuilder,然后用append()拼接,最后调用toString()赋值给String对象;
循环内拼接建议用StringBuilder或StringBuffer。
附:哔哩哔哩视频地址