StringBuffer与stringBuilder

StringBuffer与stringBuilder

对于String的学习:

final 修饰了String类所以String类是无法被修改的,并且不是基本数据类型。

当我们用双引号创建一个字符串时,jvm首先在字符串常量池中找寻具有相同值的字符串如果找到了,他将返回字符串常量池中的字符串对象引用。否则就在常量池中创建字符串对象并返回引用。

如果使用new创建字符串就需要在堆中创建它。

拼接字符串

我们使用Spring进行字符串拼接时,它会生成一个新的String并丢弃旧的String。/

这些操作肯定会在堆中产生大量垃圾冗余。于是产生了Stringbuffer(始于1.0之后)与StringBuilder(始于1.5之后)类用于对字符串的操作。
摘录自:https://developer.aliyun.com/article/787097?accounttraceid=7ccd1e5925ac4bff8b9d2ada96ac4f4arrjy
Java 中 String 与 StringBuffer 和 StringBuilder 的区别:
在 Java 1.4 之前,StringBuffer 是字符串操作的唯一选择。但是,它的一个缺点是所有公共方法都是同步的。 StringBuffer 提供线程安全性,但以性能为代价。
在大多数情况下,我们不会在多线程环境中使用 String。所以 Java 1.5 引入了一个新类 StringBuilder,除了线程安全和同步之外,它与 StringBuffer 类似。

StringBuffer 有一些额外的方法,例如 substring, length, capacity, trimToSize 等。但是,这些不是必需的,因为 String 中也有所有这些。这就是为什么这些方法从未在 StringBuilder 类中实现的原因。
StringBuffer 是在 Java 1.0 中引入的,而 StringBuilder 类是在查看 StringBuffer 的缺点后在 Java 1.5 中引入的。

假设在单线程环境中或无关线程安全,要使用 StringBuilder。反之,使用 StringBuffer 进行线程安全的操作。

关于Spring的面试体

//第一题
String s1 = "abc";
String s2 = "xyz";
String s3 = s1 + s2;
String s4 = "abc" + "xyz";
String s5 = "zbcxyz";
System.out.println(s3 == s4); // false
System.out.println(s4 == s5); // true

s1、s2都在常量池中,而s3=s1+s2,s3不会放在常量池中(只有字面常量才会放在常量池中),所以s3放在堆中,s4是两个字面常量拼接,所以会放在常量池中,内容为“abcxyz”,s5创建时,现在常量池中找到了相同的,所以两者引用相同

所以s3和s4的引用不同,s4和s5的引用相同
原文链接:https://blog.csdn.net/weixin_42193813/article/details/107725927

//第二种
String s1 = "abc";
String s2 = "xyz";
String s3 = s1 + s2;
String s4 = s3.intern();
String s5 = "abcxyz";
System.out.println(s3 == s4); // true
System.out.println(s4 == s5); // true

使用intern方法如果常量池中没有,则把对象复制一份(或对象引用)放入常量池中, 返回常量池中的对象,如果常量池中存在,则直接返回。
JDK1.7之前是复制一份放入常量池,JDK1.7之后则把对象引用到常量池。

intern方法:

intern() 方法返回字符串对象的规范化表示形式。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
String str1="aaa";
String str2=new String("aaa");
System.out.println(str1==str2);//false
System.out.println(str1==str2.intern());//true

s3存放在堆中,而创建s4时发现常量池中没有,则把s3对象复制一份放入常量池中(此时常量池中存放s3在堆中创建的“abcxyz”的地址),然后返回常量池中的对象,所以s3和s4指向同一个地址引用,结果为true

当创建s5时,发现常量池中有“abcxyz”地址,所以s5指向常量池中的地址,然后此地址再指向堆中“abcxyz”,所以s4和s5都指向常量池中的地址,结果为true

1、StringBuffer

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。

String bufffer的方法:

序号 方法描述
1 public StringBuffer append(String s) 将指定的字符串追加到此字符序列。
2 public StringBuffer reverse() 将此字符序列用其反转形式取代。
3 public delete(int start, int end) 移除此序列的子字符串中的字符。
4 public insert(int offset, int i) 将 int 参数的字符串表示形式插入此序列中。
5 insert(int offset, String str) 将 str 参数的字符串插入此序列中。
6 replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。
序号· 常用方法描述
1 int capacity() 返回当前容量。
2 char charAt(int index) 返回此序列中指定索引处的 char 值。
3 void ensureCapacity(int minimumCapacity) 确保容量至少等于指定的最小值。
4 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将字符从此序列复制到目标字符数组 dst
5 int indexOf(String str) 返回第一次出现的指定子字符串在该字符串中的索引。
6 int indexOf(String str, int fromIndex) 从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。
7 int lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。
8 int lastIndexOf(String str, int fromIndex) 返回 String 对象中子字符串最后出现的位置。
9 int length() 返回长度(字符数)。
10 void setCharAt(int index, char ch) 将给定索引处的字符设置为 ch
11 void setLength(int newLength) 设置字符序列的长度。
12 CharSequence subSequence(int start, int end) 返回一个新的字符序列,该字符序列是此序列的子序列。
13 String substring(int start) 返回一个新的 String,它包含此字符序列当前所包含的字符子序列。
14 String substring(int start, int end) 返回一个新的 String,它包含此序列当前所包含的字符子序列。
15 String toString() 返回此序列中数据的字符串表示形式。

2、StringBuilder

StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

我们来看一段代码及分析:

public class RunoobTest{
    public static void main(String args[]){
        StringBuilder sb = new StringBuilder(10);
        sb.append("Runoob..");
        System.out.println(sb);  
        sb.append("!");
        System.out.println(sb); 
        sb.insert(8, "Java");
        System.out.println(sb); 
        sb.delete(5,8);
        System.out.println(sb);  
    }
}
sb.append("Runoob..");  
 sb.append("!");
  sb.insert(8, "Java");
  sb.delete(5,8);
StringBuilder sb = new StringBuilder();
// 对象名.length() 序列长度
System.out.println(sb.length());  // 0
// 对象名.append() 追加到序列
sb.append("hello");
System.out.println(sb);  // hello
// 97代表的是是'a'
sb.appendCodePoint(97);
System.out.println(sb);  // helloa
// 链式编程
sb.append(1).append("world").append(2);
System.out.println(sb);  // helloa1world2
// 索引是5的位置替换成空格
sb.setCharAt(5, ' ');
System.out.println(sb);  // hello 1world2
// 指定位置0前插入0
sb.insert(0, 0);
System.out.println(sb);  // 0hello 1world2
// 删除索引6(包含)至索引14(不包含)的字符串
sb.delete(6, 14);
System.out.println(sb);  // 0hello
// StringBuilder类型转换成String类型
String s = sb.toString();
System.out.println(s);  // 0hello
// 以及还有截取、反转、替换等方法

总结

  • String 是不可变的,而 StringBuffer 和 StringBuilder 是可变类。
  • StringBuffer 是线程安全和同步的,而 StringBuilder 不是。这就是 StringBuilder 比 StringBuffer 快的原因。
  • 字符串连接运算符 (+) 在内部使用 StringBuilder 类。
  • 对于非多线程环境中的字符串操作,我们应该使用 StringBuilder 否则使用 StringBuffer 类。

你可能感兴趣的:(Java基础,jvm,java,面试)