something before start
说实话String在我心里一直挺神秘的,特别是之前学的时候接触到的常量池的概念(我这会儿琢磨着不会就是一个Map吧)
感觉jvm关于String的机制比较多,所以相比于之前的会多一个说明
稍微概览了一下,感觉很多实现都是没必要看的,主要记一下一些机制上的东西
String类说明
以下说明来自String源码
-
所有的字符串都是String类的实例。意思就是说字符串常量也可以调用String里的方法。
这个规则常用的地方是字符串比较的时候"常量".equals(str)
,这样就不用对变量是否取null进行多一次的判断 -
String是不可变类,创建之后就不能变化。StringBuffer可以支持变化字符串
-
Java对String对象相加,其他类转换成String提供支持 //toString
-
除非特殊说明,给构造函数传入null会抛出异常
-
String以UTF-16存储,增补字符以surrogate pair的形式存储
-
除非特殊说明,比较(compare)字符串不考虑内存地址
-
字符串拼接的实现方式由java编译器决定,取决于JDK版本,可能会用StringBuffer、StringBuilder或StringConcatFactory的方法。
注:字符串+
运算会创建一个对象,然后使用相应方法,所以效率会相应更差一点 -
字符串转换的方法通常是通过toString实现
属性
@Stable //一个域的组件(component)顶多被修改一次,即第一个非空值,他的值被称为稳定值(stable value)
private final byte[] value;
private final byte coder;
//有两种取值, 后面有很多的处理是把两种取值分开的,我猜应该是为了让性能更好点,因为LATIN1包含的是大部分编程中常用的字符,而且不需要考虑增补字符的情况。
//在构造函数里对字符串的内容进行判断来进行初始化
//LATIN1
//UTF16
//这个值由JVM注入,如果false,则字符串就一直都会是以UTF16的形式被处理。一般都是true
static final boolean COMPACT_STRINGS;
/** Cache the hash code for the string */
private int hash; // Default to 0
/**
* Cache if the hash has been calculated as actually being zero, enabling
* us to avoid recalculating this.
*/
private boolean hashIsZero; // Default to false;
方法
构造方法
String(char[] value, int off, int len, Void sig) {
if (len == 0) {
this.value = "".value;
this.coder = "".coder;
return;
}
if (COMPACT_STRINGS) {
//如果value只包含拉丁文的字符,则返回相应byte[],否则返回null
byte[] val = StringUTF16.compress(value, off, len);
if (val != null) {
this.value = val;
this.coder = LATIN1;
return;
}
}
this.coder = UTF16;
this.value = StringUTF16.toBytes(value, off, len);
}
intern
这是一个底层方法,以下是他的简单说明
- 字符串池,初始为空,由String类进行拓展 //实际上底层是hashTable
- 当
intern()
被调用,如果池中已经有相同的string对象(通过equal函数对比),则直接返回,否则将这个对象添加到字符串池中,返回指向这个对象的引用 - 所有的字符串和字符串常量都interned
public native String intern();
text-block jdk15新特性
喜极而泣
String a = """
现在
终于
可以
不用
手动拼接换行字符串了!
:D
""";
System.out.println(a);
//输出
现在
终于
可以
不用
手动拼接换行字符串了!
:D
首尾用三个引号框起来的
就是这么简单(响指
end
所以其实无论怎么去new,其实value的值都是会复用的
然后底层确实是Map
String类也有一堆工具方法,其实基本上都可以见名知意,就不多赘述了。