String源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
String 被 final 修饰,说明 String 类绝不可能被继承了,也就是说任何对 String 的操作方法,都不会被继承覆写;
String 中保存数据的是一个 char 的数组 value。值value 也是被 final 修饰的,也就是说 value 一旦被赋值,内存地址是绝对无法修改的,而且 value 的权限是 private 的,外部绝对访问不到,String 也没有开放出可以对 value 进行赋值的方法,所以说 value 一旦产生,内存地址就根本无法被修改。
相等判断
public boolean equals(Object anObject) {
// 判断内存地址是否相同
if (this == anObject) {
return true;
}
// 待比较的对象是否是 String,如果不是 String,直接返回不相等
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;
}
拆分和合并
拆分使用 split (),该方法有两个入参数。第一个是将要拆分的字符,第二个参数是一个 int 型数值,叫 limit,来限制我们需要拆分成几个元素。如果 limit 比实际能拆分的个数小,将按照 limit 的个数进行拆分。
拆分结果里面不会出现被拆分的字段
空值是拆分不掉的,仍然成为结果数组的一员
其中google提供的 Splitter ,可以达到去除空值的效果
String a =",a, , b c ,";
// Splitter 是 Guava 提供的 API
List<String> list = Splitter.on(',')
.trimResults()// 去掉空格
.omitEmptyStrings()// 去掉空值
.splitToList(a);
log.info("Guava 去掉空格的分割方法:{}",JSON.toJSONString(list));
// 打印出的结果为:
["a","b c"]
合并
合并可以使用 join 方法,此方法是静态的。
缺点
不支持依次 join 多个字符串,例如依次 join 字符串 s 和 s1,如果写成 String.join(",",s).join(",",s1) 最后得到的是 s1 的值,第一次 join 的值被第二次 join 覆盖了;
如果 join 的是一个 List,无法自动过滤掉 null 值。
google也提供了解决该方法的API
// 依次 join 多个字符串,Joiner 是 Guava 提供的 API
Joiner joiner = Joiner.on(",").skipNulls();
String result = joiner.join("hello",null,"china");
log.info("依次 join 多个字符串:{}",result);
List<String> list = Lists.newArrayList(new String[]{"hello","china",null});
log.info("自动删除 list 中空值:{}",joiner.join(list));
// 输出的结果为;
依次 join 多个字符串:hello,china
自动删除 list 中空值:hello,china
LONG
Long 最被我们关注的就是 Long 的缓存问题,Long 自己实现了一种缓存机制,缓存了从 -128 到 127 内的所有 Long 值,如果是这个范围内的 Long 值,就不会初始化,而是从缓存中拿.
private static class LongCache {
private LongCache(){}
// 缓存,范围从 -128 到 127,+1 是因为有个 0
static final Long cache[] = new Long[-(-128) + 127 + 1];
// 容器初始化时,进行加载
static {
// 缓存 Long 值,注意这里是 i - 128 ,所以再拿的时候就需要 + 128
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
为什么使用 Long 时,大家推荐多使用 valueOf 方法,少使用 parseLong 方法?
因为 Long 本身有缓存机制,缓存了 -128 到 127 范围内的 Long,valueOf 方法会从缓存中去拿值,如果命中缓存,会减少资源的开销,parseLong 方法就没有这个机制。