(JAVA面试)String StringBuffer StringBuilder详解

String

String实现了三个接口:Serializable、Comparable、CarSequence
String不是基本数据类型而是属于引用数据类型。
String是不可修改的,且java运行环境中对string对象有一个对象池保存。

实用方法

compareTo() 判断字符串的大小关系
string.substring(i,j) 分割字符串方法 左闭右合(左边包括 右边不包括)
trim() 去字符串首尾空格

类型转换

1、将字符串转换成字符数组
public char[] toCharArray();
2、将字符串转换成字符串数组
public StringI split(Sstring regex:;//regex是给定的匹配
3、将其它数据类型转化为字符串
(1)public static String valueOf(bolean b);
(2)public static String valueOf(Char C);
(3)public static String valueOf(int i);
(4)public static String valueOf(long i);
(5)public static String valueOf(double d);
(6)public static String valueOf(char[] data);
(7)public static String valuoOf(Object obj);

查找字符

public char charAt(int index);// 返回指定索引lindex位置上的字符,索引范围从0开始

在String类中提供了两种查找指定位置的字符串第一次出现的位置的方法
(1)public int indexOf(String st);// 从字符串开始检索str,并返回第-次出现的位置, 未出现返回-1
(2)public int indexOf(String str,int fromIndex);// 从字符串的第fromIndex个字符开始检索str
查找最后一次出现的位置有两种方法
(1)public int lastIndexOf(String str);
(2)public int lastIndexOf(String str,int fromIndex);
如果不关心字符串的确切位置则可使用public boolean contains(CharSequence s);

线程安全

String类中使用字符数组保存字符串,因为有“final”修饰符,所以可以知道string对象是不可变的。(注意jdk1.8以后String StringBuffer和StringBuilder都是被final修饰的)

常量池

  • 当用 String s1 = “abc” 创建对象时
  • 会首先在字符串池里面寻找是否存在abc这个字符串
  • 如果存在会在字符串池中返回他的引用
  • 如果不存在 会将abc添加到字符串池里面 然后返回引用

字符串如果是new出 就是在堆内存中开辟一个地址,即使是与字符串常量池里面的字符进行拼接 地址仍是在堆内存 不保存到字符串常量池

扩充字符串常量池

在这里插入图片描述
* 扩充字符串池 使用string.intern()方法 s3引入到了字符串常量池
* 该方法会在字符串池里面查找与该字符串有相同Unicode的字符串
* 若是存在返回其引用,否则将该字符串添加到字符串池中并返回其引用。

拼接字符串

不推荐使用 因为这种方法会创建大量String对象 占用内存过多 效率低下

String s0 = new String("31231");
s0 = s0 + "31" + "312";

例题考点

1 在遇到string类型之前,int间使用“+”还是表示数值的相加,但是遇到第一个string后, 后面就都是按string类型来了,变成字符串的拼接

System.out.println(1 + 1 + "23");//输出223

2.下面这条语句一共创建了多少个对象:String s=“a”+“b”+“c”+“d”;
String s1 = “a”;

String s2 = s1 + “b”;

String s3 = “a” + “b”;

System.out.println(s2 == “ab”);

System.out.println(s3 == “ab”);

第一条语句打印的结果为false,第二条语句打印的结果为true,这说明javac编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。

题目中的第一行代码被编译器在编译时优化后,相当于直接定义了一个”abcd”的字符串,所以,上面的代码应该只创建了一个String对象。写如下两行代码,

String s =“a” + “b” + “c” + “d”;

System.out.println(s== “abcd”);

最终打印的结果应该为true。
3.String s = new String(“xyz”);创建了几个String Object?二者之间有什么区别?

两个或一个,"xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量"xyz”不管出现多少遍,都是缓冲区中的那一个。New String每写一遍,就创建一个新的对象,它一句那个常量"xyz”对象的内容来创建出一个新String对象。如果以前就用过“xyz’,这句代表就不会创建"xyz”自己了,直接从缓冲区拿。

StringBuffer和StringBudiler

共同点

都是变量
StringBuilder与StringBuffer有公共父类AbstractStringBuilder( 抽象类 )。
抽象类与接口的其中一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。
StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(…)。只是StringBuffer会在方法上加synchronized关键字,进行同步。
最后,如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。
StringBuffer,StringBuilder实现了两个接口Serializable、CharSequence,
继承自AbstractStringBuilder类,所以可以实现字符串的修改。

区别

同样的String的实例可以通过compareTo方法进行比较,其他两个不可以。

StringBuffer是线程安全,可以不需要额外的同步用于多线程中;

StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;

StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。

拼接字符串

StringBuffer s1 = new StringBuffer("31231");//安全
s1.append("31231");
System.out.println(s1);   

PS:注意StringBuffer和StringBuilder 虽然是变量 但是只能通过创建对象的方式来创建 可以用toString()方法来转化为String类型

String StringBuffer和StringBuilder的区别

1.可变与不可变

String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
String 为不可变对象,一旦被创建,就不能修改它的值. . 对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.

StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。
char[] value;
StringBuffer:是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象 , 它只能通过构造函数来建立,
如: StringBuffer sb = new StringBuffer();
不能通过赋值符号对他进行赋值 , 如 sb = “welcome to here!”;//error
对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.向StringBuffer中赋值的时候可以通过它的append方法. sb.append(“hello”);

2.是否多线程安全

String中的对象是不可变的,也就可以理解为常量, 显然线程安全 。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是 线程安全的 。看如下源码:

1 public synchronized StringBuffer reverse() {
2 super .reverse();
3 return this ;
4 }
5
6 public int indexOf(String str) {
7 return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
8 }

StringBuilder并没有对方法进行加同步锁,所以是 非线程安全的 。

3 速度

(参考Java面试String汇总.)
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做

在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。

在大部分情况下 StringBuilder > StringBuffer
StringBuilder
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

总结一下:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值