一篇讲清楚String、StringBuffer和StringBuild
一、String篇
1、String基本介绍?
(jdk文档原文)String
类代表字符串。 Java程序中的所有字符串文字(例如"abc"
)都被实现为此类的实例。
说人话就是:String是用来保存字符串的,比如:“我好帅啊”、“123456”、"hello"这些都是字符串,而区分是否为字符串的标志就是这对双引号:""。
2、String类特性:
String是一个final类,代表不可变的字符序列。
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
String对象的字符内容是存储在一个字符数组value[]中的。
字符串不变; 它们的值在创建后不能被更改。 字符串缓冲区支持可变字符串。 因为String对象是不可变的,它们可以被共享。 例如:
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
以下是一些如何使用字符串的示例:
System.out.println("abc");
String cde = "cde";
System.out.println("abc" + cde);
String c = "abc".substring(2,3);
String d = cde.substring(1, 2);
3、为什么String是不可变的?
我们看看源码,发现value这个字符数组被final修饰了,怪不得String是不可变的。
4、String的继承图以及父类介绍
1)Serializable:
public interface Serializable
类的序列化由实现java.io.Serializable接口的类启用。不实现此接口的类将不会使任何状态序列化或反序列化。可序列化类的所有子类型都是可序列化的。序列化接口没有方法或字段,仅用于标识可串行化的语义。
为了允许序列化不可序列化的子类型,子类型可能承担保存和恢复超类型的公共,受保护和(如果可访问)包字段的状态的责任。 子类型可以承担此责任,只有当它扩展的类具有可访问的无参数构造函数来初始化类的状态。 如果不是这样,声明一个类Serializable是一个错误。 错误将在运行时检测到。
在反序列化期间,非可序列化类的字段将使用该类的public或protected no-arg构造函数进行初始化。 对于可序列化的子类,必须可以访问no-arg构造函数。 可序列化子类的字段将从流中恢复。
当遍历图形时,可能会遇到不支持Serializable接口的对象。 在这种情况下,将抛出NotSerializableException,并将标识不可序列化对象的类
2)Comparable<T>:
public interface Comparable<T>
该接口对实现它的每个类的对象强加一个整体排序。这个排序被称为类的自然排序 ,类的
compareTo
方法被称为其自然比较方法 。Collections.sort
(和Arrays.sort
)可以自动对实现此接口的对象进行列表(和数组)排序。 实现该接口的对象,可以使用如在键sorted map或作为在元件sorted set ,而不需要指定一个comparator 。一类
C
的自然顺序被说成是与equals一致当且仅当e1.compareTo(e2) == 0
对每一个e1
和C
类e2
相同的布尔值e1.equals(e2)。
请注意,null
不是任何类的实例,e.compareTo(null)
应该抛出一个NullPointerException
即使e.equals(null)
返回false
。强烈建议(尽管不需要)自然排序与等于一致。 这是因为,当没有显式比较器的排序集(和排序映射)与其自然排序与equals不一致的元素(或键)一起使用时会“奇怪地”。 特别地,这种排序集合(或排序映射)违反了根据
equals
方法定义的集合(或映射)的一般合同。
3)CharSequence:
public interface CharSequence
CharSequence
是char
值的可读序列。该界面提供统一的,只读访问许多不同类型的char
序列。char
值代表基本多语言平面(BMP)或代理中的一个字符。详见Unicode Character Representation 。此界面不会完善
equals
和hashCode
方法的一般合同。 因此,比较两个对象实现CharSequence
其结果是,在一般情况下,不确定的。 每个对象可以由不同的类实现,并且不能保证每个类都能够测试其实例以与另一个类相同。 因此,使用任意的CharSequence
实例作为集合中的元素或映射中的键是不合适的
5、创建 String 对象的两种方式
方式一、直接赋值:String s = "归海";
这种方式它首先会先从常量池查看是否有"归海" 这个数据空间,如果有就直接指向,如果没有就创建一个”归海“这个数据空间然后指向它。注意s最终指向的是常量池的空间地址。
方式二、调用构造器 String s1= new String("归海");
这种方式则是先在堆中创建空间,里面维护了value属性,指向常量池的"归海"空间。如果常量池中没有''归海'',则重新创建,如果有就直接通过value指向。注意这里最终指向的是堆中的空间地址。
经过刚才简单的介绍你应该对String有一点印象了,ok话不多说来几道练习题:
例题一:
String a = "abc';
String b = "abc'';
System.out.println(a == b) ; //true/fales
System.out.println(a.equals(b));//true/fales
例题二:
String a = new String("abc");
String b = new String("abc");
System.out.println(a == b) ; //true/fales
System.out.println(a.equals(b));//true/fales
例题三:
String a = "归海';
String b = new String("归海");
System.out.println(a == b) ; //true/fales
System.out.println(a.equals(b));//true/fales
例题四:
Person p1 = new Person();
p1.name = "归海";
Person p2 = new Person() ;
p2.name = "归海";
System.out.println(p1.name.equals(p2.name));//true/fales
System.out.println(p1.name == p2.name) ; //true/fales
System.out.println(p1.name == "归海") ; //true/fales
来说一下答案吧。
(1)T, T;
(2)F, T;
(3)F, T;
(4)T, T, T;
6、String 类常用方法
下面是 String 类支持的方法,更多详细内容,参看 Java String API 文档:
序号 | 方法描述 |
---|---|
1 | char charAt(int index) 返回指定索引处的 char 值。 |
2 | int compareTo(Object o) 把这个字符串和另一个对象比较。 |
3 | int compareTo(String anotherString) 按字典顺序比较两个字符串。 |
4 | int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写。 |
5 | String concat(String str) 将指定字符串连接到此字符串的结尾。 |
6 | boolean contentEquals(StringBuffer sb) 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。 |
7 | [static String copyValueOf(char] data) 返回指定数组中表示该字符序列的 String。 |
8 | [static String copyValueOf(char] data, int offset, int count) 返回指定数组中表示该字符序列的 String。 |
9 | boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。 |
10 | boolean equals(Object anObject) 将此字符串与指定的对象比较。 |
11 | boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。 |
12 | [byte] getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
13 | [byte] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
14 | [void getChars(int srcBegin, int srcEnd, char] dst, int dstBegin) 将字符从此字符串复制到目标字符数组。 |
15 | int hashCode() 返回此字符串的哈希码。 |
16 | int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。 |
17 | int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。 |
18 | int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。 |
19 | int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。 |
20 | String intern() 返回字符串对象的规范化表示形式。 |
21 | int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。 |
22 | int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。 |
23 | int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。 |
24 | int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 |
25 | int length() 返回此字符串的长度。 |
26 | boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。 |
27 | boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
28 | boolean regionMatches(int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
29 | String replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 |
30 | String replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
31 | String replaceFirst(String regex, String replacement) 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 |
32 | [String] split(String regex) 根据给定正则表达式的匹配拆分此字符串。 |
33 | [String] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串。 |
34 | boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始。 |
35 | boolean startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 |
36 | CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。 |
37 | String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。 |
38 | String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。 |
39 | [char] toCharArray() 将此字符串转换为一个新的字符数组。 |
40 | String toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 |
41 | String toLowerCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。 |
42 | String toString() 返回此对象本身(它已经是一个字符串!)。 |
43 | String toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 |
44 | String toUpperCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。 |
45 | String trim() 返回字符串的副本,忽略前导空白和尾部空白。 |
46 | static String valueOf(primitive data type x) 返回给定data type类型x参数的字符串表示形式。 |
不过发现没String类的效率有点低啊!这是String类因为每次更新内容都要重新开辟空间,为此java设计者还提供了StringBuilder和SreingBuffer类来增强String功能和效率。
二、StringBuffer篇
1、StringBuffer基本介绍?
1)它也是一个元老级别的类了从jdk1.0的时候就有了
2)StringBuffer是一个可变的字符序列,可以对字符内容进行更改。
3)StringBuffer的很多方法也String相同,但是StringBuffer是可变长度的。
4)StringBuffer是一个容器。
2、StringBuffer的特性:
1)线程安全,可变的字符序列。 字符串缓冲区就像一个String
,但可以修改。
2)字符缓冲可以安全的被多个线程使用。前提是这些方法必须进行同步。
3)每个字符串缓冲区都有一个容量。 只要字符串缓冲区中包含的字符序列的长度不超过容量,就不必分配新的内部缓冲区数组。 如果内部缓冲区溢出,则会自动变大
private transient char[] toStringCache; 这是StringBuffer可以更改的原因。
3、StringBuffer注意事项:
StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
StringBuffer():初始容量为16的字符串缓冲区
StringBuffer(int size):构造指定容量的字符串缓冲区
StringBuffer(String str):将内容初始化为指定字符串内容
4、StringBuffer的继承图以及父类介绍:
1)Appendable:
public interface Appendable
可附加
char
序列和值的对象。Appendable
接口必须由其实例旨在从Formatter
接收格式化输出的任何类实现 。要附加的字符应为Unicode Character Representation中描述的有效Unicode字符。 请注意,补充字符可以由多个16位
char
值组成。对于多线程访问,附加功能不一定是安全的。 线程安全是扩展和实现这个接口的类的责任。
由于此接口可能由具有不同样式的错误处理的现有类实现,因此不能保证将错误传播到调用者。
2)AbstractStringBuilder:首先这是一个类
位置:java.lang包中 |
---|
声明: abstract class AbstractStringBuilderimplements Appendable, CharSequence |
AbstractStringBuilder 类有abstract 修饰,可知它不能被实例化。AbstractStringBuilder 类有两个子类:StringBuilder和StringBuffer。 |
5、StringBuffer类常用方法:
序号 | 方法描述 |
---|---|
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 | replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符 |
6、String类和StringBuffer的区别:
1)String用于字符串操作,属于不可变类,而StringBuffer也是用于字符串操作,不同之处是StringBuffer属于可变类。
2) String是不可变类,也就是说,String对象一旦被创建,其值将不能被改变,而StringBuffer是可变类,当对象被创建后,仍然可以对其值进行修改。
3)String类每次更新实际上是更改地址,因此它的效率低。
4)StringBuffer类每次更新是更新内容,不用更新地址,因此它的效率高。
三、StringBuilder篇
1、StringBuilder基本介绍:
1)一个可变的的字符序列。提供了和SteingBuffer兼容的API。
2)StringBuilder是线程不安全的,此类设计用作简易替换为StringBuffer
在正在使用由单个线程字符串缓冲区的地方。
3)StringBuilder的主要StringBuilder
是append
和insert
方法,它们是重载的,以便接受任何类型的数据。 每个都有效地将给定的数据转换为字符串,然后将该字符串的字符附加或插入字符串构建器。
4)它的速度比StringBuffer快毕竟线程不安全换来的。
2、StringBuilder的继承图以及源码:
我们会发现和StringBuffer一模一样,所以它们的API兼容也是正常。
源码也没什么说的,因为我也不会。
3、String、StringBuffer、StringBuilder的区别:
对比String、StringBuffer、StringBuilder
String(JDK1.0):不可变字符序列 ,效率低但是复用率高。
StringBuffer(JDK1.0):可变字符序列、效率较高、线程安全。
StringBuilder(JDK 5.0):可变字符序列、效率最高、线程不安全
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder 会改变其值。
4、String、StringBuffer、StringBuilder的效率测试
代码例子:
package link;
/**
* @author 归海
* @date 2022/5/1
*/
public class Test {
public static void main(String[] args) {
long startTime = 0L;
long endTime = 0L;
StringBuffer buffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
StringBuilder builder = new StringBuilder("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
String text = "";
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
}
}
这个是 i < 80000次的结果
这个是 i < 180000次的结果
可以发现如果次数不是很大StringBuffer和StringBuilder的差距还是可以的。次数越大差距越大。
四、总结:
String、StringBuffer、StringBuilder的选择:
1、如果字符串中存在大量的修改操作,可以选择StrinBuffer和StringBuilder其中之一。
2、如果字符串中存在大量的修改操作而且在单线程的情况下,使用StringBuilder。
3、如果字符串中存在大量的修改操作而且在多线程的情况下,使用StringBuffer。
4、如果字符串修改很少、被多个对象引用,使用String。这个在配置信息的时候应用广泛。
一篇讲清楚String、StringBuffer和StringBuild的更多相关文章
- String、StringBuffer和StringBuild的区别
public class Test1 { public static void stringReplace (String text) { text = text.replace('j','i') ; ...
- String | StringBuffer | StringBuilder 比较
2016的第一天,我决定写一篇博客来纪念这一天,希望一年好运吧. String|StringBuffer|StringBuilder这三者在我们学习JAVASE核心API的时候常常出来,而且大多数入门 ...
- Java基础篇--字符串处理(StringBuffer)
字符串处理 在Java中最常将字符串作为String类型对象来处理.同时String中也提供了很多操作字符串的函数(可自行查阅资料),而本篇将介绍StringBuffer如何操作字符串. String ...
- 重温java中的String,StringBuffer,StringBuilder类
不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...
- 面试连环炮系列(二十三): StringBuffer与StringBuild的区别
StringBuffer与StringBuild的区别 频繁修改字符串时,建议使用StringBuffer和StringBuilder类.StringBuilder相较于StringBuffer有速度 ...
- String,StringBuffer,StringBuilder 的区别是什么
Java中用于处理字符串常用的有三个类: 1.java.lang.String 2.java.lang.StringBuffer 3.java.lang.StrungBuilder 一.Java St ...
- java中 String StringBuffer StringBuilder的区别
* String类是不可变类,只要对String进行修改,都会导致新的对象生成. * StringBuffer和StringBuilder都是可变类,任何对字符串的改变都不会产生新的对象. 在实际使用 ...
- String,StringBuffer与StringBuilder的区别??
转自http://blog.csdn.net/rmn190/article/details/1492013 String 字符串常量 StringBuffer 字符串变量(线程安全) StringBu ...
- String,StringBuffer,StringBuilder的区别
public static void main(String[] args) { String str = new String("hello...."); StringBuffe ...
随机推荐
- Collection框架中实现比较要实现什么接口?
Java集合框架中需要比较大小的集合包括TreeMap.TreeSet,其中TreeMap会根据key-value对中key的大小进行排序,而TreeSet则会对集合元素进行排序. 因此TreeMap ...
- Nginx HTTP负载均衡和反向代理的配置与优化
一.什么是负载均衡和反向代理 1.负载均衡 负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器具有等价的地位,都可以单独提供服务而无需其他服务的辅助.通过某种负载分担技术,将外部发送来的 ...
- android SQLite数据库(转)
Android数据库 之 SQLite数据库 Android数据库 一.关系型数据库SQLIte 每个应用程序都要使用数据,Android应用程序也不例外,Android使用开源的.与操作系统无 ...
- SVG vs Image, SVG vs Iconfont
这可能是个别人写过很多次的话题,但貌似由于兼容性的原因?图标的显示还是用着 Iconfont 或者 CSS Sprite 的形式?希望通过自己新瓶装旧酒的方式能重新引导一下问题. SVG vs Ima ...
- python-蒙特·卡罗法计算圆周率
[题目描述]蒙特·卡罗方法是一种通过概率来得到问题近似解的方法,在很多领域都有重要的应用,其中就包括圆周率近似值的计问题.假设有一块边长为2的正方形木板,上面画一个单位圆,然后随意往木板上扔飞镖,落点 ...
- 利用css3渐变效果实现圆环旋转效果
* { margin: 0; padding: 0; } .stage { width: 200px; height: 130px; margin: 100px auto; position: rel ...
- 带UI的小初高数学学习软件—艰难地用C++(QT库)实现的过程
从互相了解对方的代码思路然后确定用C++编写,到用win32写界面时变得摇摆不定的考虑着要不要改变语言,再到用QT写完界面后发现短信接口一般都不提供C++,最后到QT打包出来的可执行文件在别的设备上无 ...
- FreeRTOS学习记录--任务创建函数详解
开局一张图.一步一步分析就好. (一)什么是任务? 在多任务系统中,我们按照功能不同,把整个系统分割成一个个独立的,且无法返回的函数,这个函数我们称为任务:任务包含几个属性:任务堆栈,任务函数.任务控 ...
- rbac介绍、自动生成接口文档、jwt介绍与快速签发认证、jwt定制返回格式
今日内容概要 RBAC 自动生成接口文档 jwt介绍与快速使用 jwt定制返回格式 jwt源码分析 内容详细 1.RBAC(重要) # RBAC 是基于角色的访问控制(Role-Based Acces ...
- 7-19(排序) 寻找大富翁 (25 分)(归并排序)(C语言实现)
7-19(排序) 寻找大富翁 (25 分) 胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人.假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁. 输入格式 ...