- 1.String
- public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
- // 存储字符, final 修饰
- private final char value[];
- // 缓存 hash code, 默认 0
- private int hash;
- // 序列号
- private static final long serialVersionUID = -6849794470754667710L;
- // 声明可序列化字段
- private static final ObjectStreamField[] serialPersistentFields =
- new ObjectStreamField[0];
- }
1.1 基本属性
char value[], 用来存储字符串对象的字符数组
int hash, 用来缓存字符串的 hash code, 默认值为 0
long serialVersionUID, 用来序列化的序列版本号
ObjectStreamField[], 可序列化类的字段说明
1.2 常用构造器
- public String() {
- this.value = "".value;
- }
初始化新创建的对象, 表示空字符串 "". 请注意, 此构造函数是不需要使用的, 因为字符串是不可变的
String str = new String(); 本质上是创建了一个空的字符数组, str 的长度为 0
- public String(String original) {
- this.value = original.value;
- this.hash = original.hash;
- }
初始化新创建的对象, 表示和参数一样的字符串, 换句话说是创建了和参数一样的对象副本, 除非需要显示的声明副本, 否则该构造函数是不需要的, 因为字符串是不可变的
- public String(StringBuffer buffer) {
- synchronized(buffer) {
- this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
- }
- }
把 StringBuffer 的内容复制到 String 对象中, 随后修改 StringBuffer 对象的值, 并不会影响 String 对象
- public String(StringBuilder builder) {
- this.value = Arrays.copyOf(builder.getValue(), builder.length());
- }
把 StringBuilder 的内容复制到 String 对象中, 随后修改 StringBuilder 的值, 并不会影响 String 对象;
此构造函数是为了把 StringBuilder 转移到 String 对象, 但是推荐使用 StringBuilder 的 toString() 方法, 因为运行更快
1.3 常用方法
- // 返回字符串的长度
- public int length() {
- return value.length;
- }
- // 比较两个 String 值是否相等
- public boolean equals(Object anObject) {
- if (this == anObject) {
- return true;
- }
- 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;
- }
- // 生成 hash code
- 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;
- }
equals 方法的判断流程:
首先判断两个对象是否相同, 若相同返回 true; 若不同, 下一步
判断参数是否为 String 对象, 若不是, 返回 false; 若是, 下一步
判断两个 String 的长度是否相等, 若不是, 返回 false; 若是, 下一步
按字符数组索引依次比较字符, 如果有任一不相同, 返回 false, 否则返回 true
1.2 为什么说 String 是不可变对象?
存储字符的数组 value[] 是 final 修饰的, 值不可更改.
2. AbstractStringBuilder
可变的字符序列, StringBuilder 和 StringBuffer 都继承了该类, 要了解 StringBuilder 和 StringBuffer 首先先了解 AbstractStringBuilder.
2.1 基本属性
- abstract class AbstractStringBuilder implements Appendable, CharSequence {
- /**
- * The value is used for character storage.
- */
- char[] value;
- /**
- * The count is the number of characters used.
- */
- int count;
- }
char[] value: 存储字符的数组
int count: 使用的字符的数量
2.2 构造器
- /**
- * 无参构造器, 用于子类序列化
- */
- AbstractStringBuilder() {
- }
- /**
- * 指定字符数组容量
- */
- AbstractStringBuilder(int capacity) {
- value = new char[capacity];
- }
2.3 常用方法
- /**
- * 返回字符的数量
- */
- @Override
- public int length() {
- return count;
- }
- /**
- * 返回当前可存储字符的最大数量, 即容量
- */
- public int capacity() {
- return value.length;
- }
- /**
- * 保证当前容量大于等于指定的最小数量 minimumCapacity, 会调用扩容方法
- */
- public void ensureCapacity(int minimumCapacity) {
- if (minimumCapacity> 0)
- ensureCapacityInternal(minimumCapacity);
- }
- /**
- * 扩容, 只有 minimumCapacity 大于当前容量, 才会 copy 数组扩容
- */
- private void ensureCapacityInternal(int minimumCapacity) {
- // overflow-conscious code
- if (minimumCapacity - value.length> 0) {
- value = Arrays.copyOf(value,
- newCapacity(minimumCapacity));
- }
- }
- /**
- * 当前对象拼接字符串 str
- * 如果参数为 null, 那么最终字符串为 "null", 如果参数类型为 boolean, 那么返回的是 "true" 或 "false"
- * 例 1: "abc".append(null) = "abcnull"
- * 例 2: "abc".append("def") = "abcdef"
- */
- public AbstractStringBuilder append(String str) {
- if (str == null)
- return appendNull();
- int len = str.length();
- ensureCapacityInternal(count + len);
- str.getChars(0, len, value, count);
- count += len;
- return this;
- }
- 3. StringBuilder
可变的字符序列, 非线程安全, StringBuilder 和 StringBuffer 的实现方法很相似, 区别在于是否线程安全, 在单线程的情况下可使用 StringBuilder, 因为它比 StringBuffer 运行更快. StringBuilder 继承了 AbstractStringBuilder 类.
3.1 基本属性
继承父类
3.2 构造器
- public final class StringBuilder extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence{
- /**
- * 序列号
- */
- static final long serialVersionUID = 4383685877147921099L;
- /**
- * 默认容量 16
- * initial capacity of 16 characters.
- */
- public StringBuilder() {
- super(16);
- }
- /**
- * 指定初始容量
- */
- public StringBuilder(int capacity) {
- super(capacity);
- }
- /**
- * 把 String 字符串初始化到对象中, 容量变为 str 的长度 + 16
- */
- public StringBuilder(String str) {
- super(str.length() + 16);
- append(str);
- }
- /**
- * 把字符初始化到对象中, 容量变为字符的长度 + 16
- */
- public StringBuilder(CharSequence seq) {
- this(seq.length() + 16);
- append(seq);
- }
3.3 常用方法
同父类
4. StringBuffer
可变的字符序列, 线程安全, StringBuffer 继承了 AbstractStringBuilder 类.
4.1 基本属性
继承父类, 同时还有以下属性
- public final class StringBuffer extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence{
- /**
- * 最后一次调用 toString 返回值的缓存
- * 当 StringBuffer 被修改时该缓存被清除
- */
- private transient char[] toStringCache;
- /** 序列号 */
- static final long serialVersionUID = 3388685877147921107L;
- }
4.2 构造器
同 StringBuilder
4.3 常用方法
与 StringBuilder 方法基本相同, 区别在于在 StringBuilder 的方法上加了 synchronized 锁. 不同的地方还有以下这种情况
- @Override
- public synchronized StringBuffer append(String str) {
- toStringCache = null;
- super.append(str);
- return this;
- }
- @Override
- public synchronized String toString() {
- if (toStringCache == null) {
- toStringCache = Arrays.copyOfRange(value, 0, count);
- }
- return new String(toStringCache, true);
- }
每次调用 toString 的时候, 都会创建一个缓存 toStringCache, 在每次修改对象的时候清空缓存, 但是这里的缓存具体什么作用呢? 大家可以在评论区留言!
5. 总结
综上所述, 可以得出相同点是: 都可以创建字符串, 不同在于 String 是不可变的, 不存在线程安全问题; StringBuilder 和 StringBuffer 字符串是可变的, StringBuilder 线程不安全, 适合单线程使用, StringBuffer 线程安全, 适合多线程; 对于频繁需要字符串的拼接操作时, 不建议使用 String, 因为每次都需要创建一个 String 对象.
来源: https://www.cnblogs.com/iceblow/p/11159120.html