String 系列:
在前面的文章我们从源码分析了 String 的底层结构,本篇我们就来看看 String 的有哪些常用方法,及这些方法的底层实现。
1. equals(比较)
public boolean equals(Object anObject) {
// 1.判断内存地址是否相同
if (this == anObject) {
return true;
}
// 2.待比较的对象是否是 String,如果不是 String,直接返回不相等
if (anObject instanceof String) {
// 注:instance使其父类也为true
String anotherString = (String)anObject;
int n = value.length;
// 3.两个字符串的长度是否相等,不等直接返回不相等
// 注:同一个类中可以直接调用private属性
if (n == anotherString.value.length) {
// 注:这里先用一个数组存下来value是为了下面代码的可读性
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 4.依次比较每个字符是否相等,若有一个不等,直接返回不相等
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
2.subString(截取)
public String substring(int beginIndex, int endIndex) { // 左闭右开
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
// 调用构造函数
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
public String substring(int beginIndex)
- substring 方法的底层使用的是字符数组范围截取的方法 :Arrays.copyOfRange(字符数组, 开始位置, 结束位置); 从字符数组中进行一段范围的拷贝。
- 返回一个新的String
3.replace & replaceAll(替换)
public String replace(char oldChar, char newChar) { // 字符替换,全部
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
// 1.整体遍历一遍,看有无需要被替换字符
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
// 2.1 若有,再创建一个新数组,然后替换后放入
if (i < len) {
char buf[] = new char[len];
// 注:这里是先将 i 之前的直接赋给新数组buf
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++;
}
// 重新构造一个String
return new String(buf, true);
}
}
// 2.2 若无,则直接返回本身
return this;
}
public String replaceFirst(String regex, String replacement) { // 只替换第一次出现的字符串
// 正则表达式
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
public String replaceAll(String regex, String replacement) { // 字符串替换,全部
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
- 当然我们想要删除某些字符,也可以使用 replace 方法,把想删除的字符替换成 “” 即可。
- 首字母大写转小写: name.substring(0, 1).toUpperCase()/toLowerCase() + name.substring(1)
4.split & join
1)split (分割)
字符串分割,返回string[]
public String[] split(String regex, int limit) // regex:分隔符 ,limit:拆分的个数
public String[] split(String regex) // return split(regex, 0);
示例:对字符串 s 进行各种拆分
String s ="boo:and:foo";
// 演示的代码和结果是:
s.split(":") // 结果:["boo","and","foo"]
s.split(":",2) // 结果:["boo","and:foo"]
s.split(":",5) // 结果:["boo","and","foo"]
s.split(":",-2) // 结果:["boo","and","foo"]
s.split("o") // 结果:["b","",":and:f"]
s.split("o",2) // 结果:["b","o:and:foo"]
2) join (连接)
字符串拼接,返回字符串
// delimiter:分隔符,elements:数据(list/array)
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// 底层是StringBuilder.append()
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
示例:
List<String> names=new ArrayList<String>();
names.add("1");
names.add("2");
names.add("3");
System.out.println(String.join("-", names)); // 1-2-3
String[] arrStr=new String[]{"a","b","c"};
System.out.println(String.join("-", arrStr)); // a-b-c
5.indexOf & charAt (查找)
1)indexOf(返回索引)
indexOf返回index,没找到就返回-1
public int indexOf(int ch, int fromIndex) {
final int max = value.length;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= max) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
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);
}
}
2)charAt(返回字符)
charAt返回指定索引的char
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
6.toCharArray & getBytes
1)toCharArray(->char数组)
底层就是char数组存储的,所以直接返回char数组就行
注:这里不能直接将value返回,因为value是final不可变的,那么返回后使用者也无法操作
public char[] toCharArray() {
// 新建一个数组,拷贝过去返回
char result[] = new char[value.length];
// arraycopy(src, srcPos, dest, destPos, length)
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
2)getBytes(->二进制数组)
在生活中,我们经常碰到这样的场景,进行二进制转化操作时,本地测试的都没有问题,到其它环境机器上时,有时会出现字符串乱码的情况,这个主要是因为在二进制转化操作时,并没有强制规定文件编码,而不同的环境默认的文件编码不一致导致的。
我们也写了一个 demo 来模仿一下字符串乱码:
String str ="nihao 你好 喬亂";
// 字符串转化成 byte 数组,转化成ISO-8859-1编码的二进制数组
// 注:ISO-8859-1编码格式不能支持所有的汉字,所以大概率乱码
byte[] bytes = str.getBytes("ISO-8859-1");
// byte 数组转化成字符串
String s2 = new String(bytes);
log.info(s2);
结果打印为:nihao ?? ??
打印的结果为??,这就是常见的乱码表现形式。是不是我把代码修改成 String s2 = new String(bytes,“ISO-8859-1”); 就可以了?这是不行的。主要是因为 ISO-8859-1 这种编码对中文的支持有限,导致中文会显示乱码。唯一的解决办法,就是在所有需要用到编码的地方,都统一使用 UTF-8,对于 String 来说,getBytes 和 new String 两个方法都会使用到编码,我们把这两处的编码替换成 UTF-8 后,打印出的结果就正常了。
7.valueOf & toString
转换String:new String(~~) 或 valueOf() 或 toString()
// 注:value是个静态方法,可以将基本类型和Object转换为String
public static String valueOf(Object obj) {
// 转换对象时调用的也是toString,但允许null
// 因此在做一些操作时要慎重,如Integer.valueOf(str);这是就会报错提示类型转换出错
return (obj == null) ? "null" : obj.toString(); // 当obj==null时,"null"
}
public static String valueOf(int i) {
// 先装箱成Integer再转换为String
return Integer.toString(i);
}
总结:对象 --> String :toString 基本类型 --> new String(~~)
8.getChars(拷贝)
将当前字符串(value)拷贝到另一个数组(dst)
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
// 直接调用System.arraycopy,value就是当前字符串
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}






还没有评论,来说两句吧...