在之前的文章中我们曾简单介绍过String这个引用类型变量,其实它还有许多特性,还有StringBuffer和StringBuilder这两个方法在字符串操作中也有非常重要的地位,接下来就由小编带大家梳理一下吧👊
目录
一、String
1、构造方法
2、字符串的不可变性
3、字符串的比较
4、 String的常用方法:
二、StringBuider和StringBuffer
1、字符串的拼接
2、StringBuider与StringBuffer
总结
一、String
1、构造方法
String类提供的构造方式非常多,常用的就以下两种:
public static void main(String[] args) {
// 使用常量串构造
String s1 = "hello";
System.out.println(s1);
// 直接newString对象
String s2 = new String("hello");
System.out.println(s1);
}
注意:
1、String是引用类型,内部并不存储字符串本身
2. 在Java中“”引起来的也是String类型对象
那么这两种对象的存储方式有什么区别呢?
在s1使用常量串构造时,会直接在字符串常量池中创建字符串,在栈中直接存储字符串在字符串常量池中相应的位置
在s2通过new String对象的方式实例化字符串时,由于其字符串内容与s1一致,不会在常量池中创建新的对象,此时字符串对象存储在堆中,在堆中存储了对应字符在常量池中的位置
这样做有什么好处呢?就是所有的字符只用在字符串常量池中创建一次就行了,后续创建的相同的字符串只需引用对应的位置即可,大大提高了空间资源的利用效率
2、字符串的不可变性
String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
1.
String类在设计时就是不可改变的,String类实现描述中已经说明了
以下来自JDK1.8中String类的部分实现:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
可以看出:
1. String类被final修饰,表明该类不能被继承
2. value被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
2.
所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
如在以下代码中:
String s1="hello";
String s2="hello";
s1="world";
s1发生改变时,s2并不会改变指向,s1会重新分配内存地址进行赋值
String字符串具有不可变性,当字符串重新赋值时,不会在原来的内存地址进行修改,而是重新分配新的内存地址创建新的对象进行赋值
注意:
字符串不可变不是因为其内部保存字符的数组被final修饰了,因此不能改变。 不是因为String类自身,或者其内部value被final修饰而不能被修改。
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
3、字符串的比较
1.
==比较是否引用同一个对象
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 10;
// 对于基本类型变量,==比较两个变量中存储的值是否相同
System.out.println(a == b); // false
System.out.println(a == c); // true
// 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // false
System.out.println(s1 == s4); // true
}
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。
2.
boolean equals(Object anObject) 方法:按照字典序比较
字典序:字符在ASCII码中的顺序
public boolean equals(Object anObject) {
// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
if (this == anObject) {
return true;
}
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
if (anObject instanceof String) {
// 将anObject向下转型为String类型对象
String anotherString = (String) anObject;
int n = value.length;
// 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 4. 按照字典序,从前往后逐个字符进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
}
3、int compareTo(String s) 方法: 按照字典序进行比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
}
4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
4、 String的常用方法:
二、StringBuider和StringBuffer
1、字符串的拼接
让我们先来看一下下面这个问题:
public static void main(String[] args) {
String s1 = "abc";
s1=s1+"def";
System.out.println(s1);
}
//以上代码创建了几个对象?
答案是三个
首先语句“String s1 = new String(“abc”);”会在字符串中创建一个对象”abc”,在执行语句”s1=s1+”def”;”时,会先创建一个对象“def”,然后在创建两个对象相加后的结果“abcdef”
这时我们发现看似简单的一个拼接操作,竟然需要创建三个对象,其效率可想而知是非常低下的,因此我们在平时应用中一般会避免这样直接通过“+”进行字符串的拼接。那么我们该怎么去拼接呢?这时候我们就要介绍StringBuider和StringBuffer了
2、StringBuider与StringBuffer
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。他们的底层原理与String类似,都是通过数组来完成对字符串的存储,其默认长度为16,当实例化一个StringBuider对象时,会根据创建字符串的长度来初始化内存,数组的内存为“创建字符的长度+16”,即在进行修改字符串的操作时有16个字符的空间可供操作,在对字符串进行修改时,会自动检测当前char数组是否装的下,如果超出数组范围,会对char数组进行扩容。
扩容机制:创建一个新的char数组对象,其长度一般为原数组的两倍,接着判断是否足够存储新的字符串,如果不够再进行扩容,以此类推,直到创建的数组足够存储新的字符串为止。然后将新字符串的内容存储到新数组,最后将指针指向新的数组
常用方法:
String和StringBuilder最大的区别在于
String的内容无法修改,而StringBuilder的内容可 以修改。频繁修改字符串的情况考虑使用StringBuilder
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法
【面试题】String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer大多数方法都使用了synchronized实现了同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
注意:在单线程的条件下,StringBuilder的运行效率要高于StringBuffer,因此在单线程的情况下一般选用StringBuilder,在多线程的情况下优先选用StringBuffer
总结
那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。作者还是一个萌新,如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊
版权声明:本文为博主作者:初晴~原创文章,版权归属原作者,如果侵权,请联系我们删除!