String
String在Java中实际上是以字符数组的方式进行存储的,并且通过源码可以看出。
char val[] = value;
在String中每次调用都是将它的value重新复制给另一个新的字符数组,所以我们不能更改它原本的值,而且value也不能被子类继承,所以String是不可更改的。
有一种情况String的值可以进行修改【反射】。后面在说
String类中的属性
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
//字符数组,存储字符串的值
private final char value[];
//字符串类型的hash值,默认是0;
private int hash;
//String类的序列化ID,通过ID来识别软件版本
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
}
/*
*StringBuffer:线程安全的带缓存的String,可变的字符串
*/
String str = "abc"; //创建了一个对象
String str1 = new String("def");//创建了两个对象
str1 = str1 + str;//创建了一个"abcdef"字符串对象,底层使用了StringBuffer的append();
//String str = "abc";
char data[] = {'a','b','c'};
String str == new String(data);
构造函数
/*无参构造*/
//不能进行追加,删除等操作,只能进行覆盖操作
public String(){
this.value = "".value;
}
//将参数的value和hash值都直接赋值给新创建的对象
public String (String original){
this.value = original.value;
this.hash = original.hash;
}
//截取字符串的子串,substring就是调用此构造函数
public String(char value[]/*截取字符串的字符数组*/, int offset/*开始的位置*/, int count/*截取的长度*/){
if(offset < 0){
throws new StringIndexOutOfBoundsException(offset);
}
if(count <= 0){
//截取长度不能小于0
if(count < 0){
throws new StringIndexOutOfBoundsException(count);
}
//count == 0时就代表没有进行截取,返回传入的value值
if(offset <= value.length){
this.value = "".value;
return;
}
}
//如果offset超届抛出异常
if(offset > value.length - count){
throws new StringIndexOutOfBoundsException(offset+count);
}
//都没有问题的时候
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
String类的方法
hashCode
获取字符串的hash码
//String中的hashCode
//在String中进行重写
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;
}
//Object中的hashCode
//看不见具体的实现方法,它自动给你返回一个hash值
public native int hashCode();
equals
字符串进行比较,看是否相等
//Object中的equals
public boolean equals(Object obj){
return (this == obj) //比较内存值
}
//String中的equals
public boolean equals(Object anObject){
if(this == anObject){
return true;
}
//测试anObject是否是String的实例
if(anObject instanceof String){
//将anObject强制转换成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;
}
charAt
获取想要位置的字符
public char charAt(int index){
if((index < 0) || (index >= value.length)){
//索引位置超出界限,抛出异常
throw new StringIndexOutOfBoudsException(index);
}
//返回索引位置的字符
return value[index];
}
substring
剪下一段字符串
public String substring(int beginIndex){
if(beginIndex < 0){
//超出界限异常
throw new StringIndexOutOfBoudsException(beginIndex);
}
//剪切的长度
int subLen = value.length - beginIndex;
//剪切的长度不能超过字符串的长度
if(subLen < 0){
throws new StringIndexOutOfBoudsException(subLen);
}
//如果index从0开始就返回字符串全部,不然就新建一个字符串返回
return (beginIndex == 0) ? this : new String(value,beginIndex,subLen);
}
indexOf
查找字符在字符串中的位置
public int indexOf(int ch/*传入字符时自动转化为int*/){
return indexOf(int ch, int fromIndex/*开始查找的位置*/);
}
//进行重载
public int indexOf(int ch, int fromIndex){
final int max = value.length;
if(fromIndex < 0){
//如果输入错误的index那么让函数从头开始查找
fromIndex = 0;
} else if(fromIndex >= max){
//选择范围超出了界限
return -1;
}
//查找通用字符,在java中存储的值通常都是小于MIN的
//MIN_SUPPLEMENTARY_CODE_POINT = 0x010000
if(ch < Character.MIN_SUPPLEMENTARY_CODE_POINT){
final char[] value = this.value;
for(int i = fromIndex; i < max; i ++){
//找到后返回下标
if(value[i] == ch){
return i;
}
}
//没有找到
return -1;
} else {
//查找的是补充字符,不是通用字符
return indexOfSupplementary(ch, fromIndex);
}
}
replace
替换字符
public String replace(char oldChar, char newChar){
//要进行替换的字符不能相同,相同的话就相当于没有替换
if(oldChar != newChar){
int len = value.length;
int i = -1;//记录是否有需要替换的字符
char[] val = value;//避免直接操作原字符串
//遍历查看需要替换字符的位置
while(++i < len){
if(val[i] == oldChar){
break;
}
}
//进行替换
if(i < len){
//替换后的字符串
char buf[] = new char[len];
//在遇到第一个需要替换的字符前直接进行复制
for(int j = 0; j < i; j ++){
buf[j] = val[j];
}
while(i < len){
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i ++;
}
//返回替换后的字符串对象
return new String (buf, true);
}
}
return this;
}
trim
去除字符串中两头的空格,在ASCII码中,空格是可见字符的最小值。
public String trim(){
int len = value.length;
int st = 0;//字符串的开始位置
char[] val = value;
//找到可见字符的起始位置
while((st < len) && (val[st] <= ' ')){
//遇见不可见字符则起始位置向后加
st ++;
}
//找到可见字符的结束位置
while((st < len) && val[len - 1] <= ' '){
//遇见不可见字符则结尾向前加
len --;
}
//将字符串从st开始到len结束进行剪切
return ((st > 0) || (len < value.length))/*最少有一个空格被解决*/ ? substring(st,len) : this/*没有空格被消除*/;
}
split
按照给定的规则将字符串分割成数组
public String[] split(String regex){
return split(regex, 0); //进行重载,从字符串头开始
}
public String[] split(String regex, int limit){
char ch = 0;
/*
*regex为一个字符时,这个字符不能为正则的元字符,例如"^$.+\\?{}[]"等
*regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母
*/
if(((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)/*regex为一个字符时,这个字符不能为正则的元字符*/ ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&/*regex是两个字符的时候并且第一个是'\'时,第二个不能时数字或字母*/
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE)){
int off = 0;
int next = 0;
//匹配的次数,没有设置时默认查询到字符串结束
boolean limited = limit > 0;
//存放结果的数组
ArrayList<String> list = new ArrayList<>();
while((next = indexOf(ch, off)) != -1/*查询regex在String中的位置,确认String中有regex的存在,等于this.indexOf(ch, off)*/){
if(!limited || list.size() < limit - 1){
//没有进行次数初始化,或者当前数组的大小小于规定的次数
//将不包含regex的子字符串放入数组中
list.add(substring(off,next));
//off直接到已经查到的regex位置加1,跳过现在的regex
off = next + 1;
} else {
//现在数组的大小已经等于limit - 1,只需要进行最后一次操作
list.add(substring(off, value.length));
off = value.length;
break;
}
}
if(off == 0){
//没有找到字符串中的regex
return new String[]{this};
}
if(!limited || list.size() < limit){
//传入的limit > 字符串中regex的次数,需要将剩余的部分添加到数组中
list.add(substring(off, value.length));
}
//构造结果
int resultSize = list.size();
if(limit == 0){
//没有传入参数或者传入的时0时,将list最后面的空数据删除掉
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize --;
}
}
//返回结果
String result[] = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
如果没有使用第51行的代码的话将会造成下面的这个结果
"boo:foo:boo".split("0",0)
-----------result--------------
{"b","",":f","",":b",""}