Java String、StringBuffer、StringBuilder类解析
String、StringBuffer、StringBuilder类解析
概述
String类:代表字符串。
特点
- String实现了Serializable接口,表示String是可序列化的
- 实现了Comparable接口
- 实现了CharSequence(字符序列接口)
- String类中用于存储字符的数组
value[]
是final类型的 - String代表不可变的字符序列,具有不可变性。
- 被final修饰,无法被继承
String类的部分源码:
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0// ...
}
String对象的创建
方式一: 字面量赋值
String s = "hello";
变量s中存储的地址是常量池当中对应的地址值。
方式二: 使用new关键字
String s1 = new String();// this.value = original.value;
String s2 = new String(String original);// this.value = Arrays.copyOf(value, value.length);
String s3 = new String(char[] a);// offset: 起始下标, count字符个数
String s4 = String(char value[], int offset, int count);
以上s1, s2, s3, s4保存的地址值都是 数据在堆空间中开辟空间后对应的地址值。
String的不同拼接方式对比
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
String s8 = s6.intern();System.out.println(s3 == s4); // true
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s6); // false
System.out.println(s5 == s7); // false
System.out.println(s6 == s7); // false
System.out.println(s3 == s8); // true
总结:
- 如果拼接方式是字面量拼接,那么拼接结果是在常量池中的。
- 如果拼接方式是变量 + 字面量、变量 + 变量,只要有变量参与,就是在堆中创建对象。
- 如果拼接结果调用的
intern()
方法,返回值就在常量池中。
一道String相关面试题
public class StringTest {String s = new String("good");char[] ch = {'t' , 'e' , 's' , 't' };public void change(String str, char[] ch) {str = "hello";ch[0] = 'b';}public static void main(String[] args) {StringTest ex = new StringTest();ex.change(ex.s, ex.ch);System.out.println(ex.s); // goodSystem.out.println(ex.ch); // best}
}
解析:
方法的参数类型是引用数据类型,传递的是地址值,一般情况下会改变引用值,但是参数是String类型的,具有不可变性,所以不会发生改变,还是原来的值。
String常用方法
方法 | 说明 |
---|---|
int length() | 返回字符串的长度: return value.length |
char charAt(int index) | 返回某索引处的字符return value[index] |
boolean isEmpty() | 判断是否是空字符串:return value.length == 0 |
String toLowerCase() | 使用默认语言环境,将 String 中的所有字符转换为小写 |
String toUpperCase() | 使用默认语言环境,将 String 中的所有字符转换为大写 |
String trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
boolean equals(Object obj) | 比较字符串的内容是否相同 |
boolean equalsIgnoreCase(String anotherString) | 与equals方法类似,忽略大 小写 |
String concat(String str) | 将指定字符串连接到此字符串的结尾。等价于用“+” |
int compareTo(String anotherString) | 比较两个字符串的大小 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。 |
String substring(int beginIndex, int endIndex) | 返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。 |
boolean endsWith(String suffix) | 测试此字符串是否以指定的后缀结束 |
boolean startsWith(String prefix) | 测试此字符串是否以指定的前缀开始 |
boolean startsWith(String prefix, int toffset) | 测试此字符串从指定索引开始的 子字符串是否以指定前缀开始 |
boolean contains(CharSequence s) | 当且仅当此字符串包含指定的 char 值序列 时,返回 true |
int indexOf(String str) | 返回指定子字符串在此字符串中第一次出现处的索引 |
int indexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右边出现处的索引 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 注:indexOf和lastIndexOf方法如果未找到都是返回-1 |
String replace(char oldChar, char newChar) | 返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有 oldChar 得到的。 |
String replace(CharSequence target, CharSequencereplacement) | 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 |
String replaceAll(String regex, String replacement) | 使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串。 |
String replaceFirst(String regex, String replacement) | 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 |
boolean matches(String regex) | 告知此字符串是否匹配给定的正则表达式。 |
String[] split(String regex) | 根据给定正则表达式的匹配拆分此字符串。 |
String[] split(String regex, int limit) | 根据匹配给定的正则表达式来拆分此 字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。 |
String与包装类和基本数据类型之间的转换
String -> 包装类、基本数据类型
调用parseXxx(String s)
方法
String str = "123";
String str1 = "123.456";
int parseInt = Integer.parseInt(str);
double parseDouble = Double.parseDouble(str1);
基本数据类型 -> String
int num1 = 1;
Integer num2 = new Integer(1);
String s1 = String.valueOf(num1);
String s2 = String.valueOf(num2);
StringBuffer和StringBuilder
String、StringBuffer、StringBuilder三者的异同?
- String: 不可变的字符序列,底层使用char数组存储
- StringBuffer: 可变的字符序列,线程安全的,但是效率低,底层使用char数组存储
- StringBuilder: 可变的字符序列,JDK5.0新增的,线程不安全的,效率高,底层使用char数组存储
StringBuffer
java.lang.StringBuffer
代表可变的字符序列,JDK1.0
中声明,可以对字符串内容进行增删,此时不会产生新的对象。- 很多方法与String相同
- 作为参数传递时,方法内部可以改变值
源码分析
StringBuffer类继承了抽象类AbstractStringBuilder,继承了属性char[] value
,用于存储字符。
public final class StringBufferextends AbstractStringBuilderimplements Serializable, CharSequence
{// ...
}
抽象类:AbstractStringBuilder
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;// ...
}
创建一个StringBuffer类的对象必须使用关键字new的方式进行创建。
调用StringBuffer类的空参构造器时回调用父类的构造器,将char[]初始大小设置为16。
/*** Constructs a string buffer with no characters in it and an* initial capacity of 16 characters.*/
public StringBuffer() {super(16);
}// 父类的构造器/*** Creates an AbstractStringBuilder of the specified capacity.*/
AbstractStringBuilder(int capacity) {value = new char[capacity];
}
因为StringBuffer中用于存储字符的数组是可变的,所以可以对这个字符进行添加、修改、删除等操作。
所以有一个问题,那就是默认长度是16,如何实现扩容?
来看看StringBuffer中的append方法:
// 重写了父类的append方法,但是在重写的方法中还是调用了父类的append方法
// 并且重写后的方法是线程安全的
@Override
public synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;
}
再来看看父类中的append方法:
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;
}// ensureCapacityInternal方法处理是否需要进行扩容
private void ensureCapacityInternal(int minimumCapacity) {// overflow-conscious codeif (minimumCapacity - value.length > 0) {// 调用Arrays中的copyOf方法,将原来的数组内容复制给新的数组value = Arrays.copyOf(value,newCapacity(minimumCapacity)); // 实际的扩容方法}
}// newCapacity
private int newCapacity(int minCapacity) {// overflow-conscious codeint newCapacity = (value.length << 1) + 2; // 默认情况下是原来的大小乘2在加上2if (newCapacity - minCapacity < 0) {newCapacity = minCapacity; // 如果容量还是不够,就将minCapacity作为容量大小}return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) // 如果需求容量更大的话在进一步处理? hugeCapacity(minCapacity): newCapacity;
}
但是为了避免频繁的扩容操作,所以一般推荐使用以下构造器创建StringBuffer对象:
一开始就指定容量大小,避免扩容操作。
public StringBuffer(int capacity) {super(capacity);
}
StringBuilder
StringBuilder与StringBuffer一样,都实现了AbstractStringBuilder类,StringBuilder与StingBuffer的构造器和append方法几乎一致,不同的是StringBuffer中的方法是线程安全的,被synchronized修饰,而StringBuilder中的方法都是线程不安全的。
如:
Stringbuffer
@Override
public synchronized int length() {return count;
}
StringBuilder
@Override
public int length() {return count;
}
StringBuffer和StringBuilder中常用方法
方法 | 说明 |
---|---|
append(xxx) | 提供了很多的重载的append()方法,用于进行字符串拼接 |
delete(int start,int end) | 删除指定位置的内容 |
replace(int start, int end, String str) | 把[start,end)位置替换为str |
insert(int offset, xxx) | 在指定位置插入xxx |
reverse() | 把当前字符序列逆转 |
当append和insert时,如果原来value数组长度不够,可扩容。
如上这些方法支持方法链操作。
方法链的原理:方法逻辑结束后return this;
此外,还定义了如下的方法:
- public int indexOf(String str)
- public String substring(int start,int end)
- public int length() public char charAt(int n )
- public void setCharAt(int n ,char ch)
String、StringBuffer、StringBuilder三者效率对比
测试代码
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
//开始对比
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
执行结果
StringBuffer的执行时间:6
StringBuilder的执行时间:2
String的执行时间:887
总结:
效率按大小排序:StringBuilder > StringBuffer > String
Java String、StringBuffer、StringBuilder类解析相关推荐
- `java`学习笔记(十二)`Java`--`String``StringBuffer``StringBuilder`
Java–String&&StringBuffer&&StringBuilder 文章目录 `Java`--`String`&&`StringBuffe ...
- 重温java中的String,StringBuffer,StringBuilder类
不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...
- Java String StringBuffer StringBuilder
(二)StringBuffer java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删.很多方法和String相同,但是StringBuffer是可变长度的 Stri ...
- 浅谈 Java 字符串(String, StringBuffer, StringBuilder)
我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...
- Java String,StringBuilder和StringBuffer的区别 StringBuilder StringBuffer String
可以证明,字符串操作是计算机程序设计中最常见的行为. String:不可变的对象,对String对象进行改变的时候其实都等同于生成了一个新的String对象,然后将引用指向新的String对象,原St ...
- 2019-7-9 [JavaSE] String ,StringBuffer,StringBuilder比较 装箱和拆箱 日期类 正则
文章目录 1.StringBuffer类 方法: 利用StringBuffer开头与结束的时间计算: String ,StringBuffer,StringBuilder比较 2.装箱和拆箱 3.日期 ...
- java中 String StringBuffer StringBuilder的区别
* String类是不可变类,只要对String进行修改,都会导致新的对象生成. * StringBuffer和StringBuilder都是可变类,任何对字符串的改变都不会产生新的对象. 在实际使用 ...
- StringBuffer类,StringBuffer类和String的区别、String,StringBuffer,StringBuilder之间的区别
1.概述 StringBuffer是一个线程安全的可变序列. 2.StringBuffer与String区别 (1)StringBuffer的长度和内容都可以发生改变,String却不行 (2)Str ...
- Java中的String,StringBuffer,StringBuilder有什么区别?
相信有很多同学都是经常使用String的,或者也或多或少的听说过StringBuffer,StringBuilder,那么在经常遇见的面试题中(标题),到底这三个的区别是什么呢?让我们来一探究竟! S ...
最新文章
- Freemarker自定义标签
- jQuery的DOM操作之选择元素
- 【翻译】卡通图解DNS,你的信息怎么被泄露的?
- 山东师范大学志愿推荐系统邀请码_快看点邀请码填写HGC1QK快看点邀请码填写HGC1QK快看点邀请码大家千万不要乱填写哦...
- 双向循环链表:鸿蒙轻内核中数据的“驿站”
- java构造方法与重载牛肉粉,IT兄弟连Java基础视频教程
- python自动登录灯塔党建_python 奇淫技巧之自动登录 哔哩哔哩
- 让电脑「读懂」你的思想——java工程师的职业规划
- echarts大数据多图表绘制卡顿解决方案
- Typora主题下载
- Hunter’s Apprentice (猎人的学徒)——【Green 公式( 判断多边形边界曲线顺/逆时针】
- uni-app实现PDF预览功能(避坑看这)
- 后缀是lnk是什么文件_后缀lnk是什么文件格式(lnk文件怎么恢复word)
- 知乎高赞:拼多多和国家电网,选哪个?
- Linux.配置Hadoop环境的一些问题解决
- 数据库双活和ALWAYSON相比的四大优势
- 猫耳FM音频转换成MP3格式
- Excel 2013 VlookUp函数使用
- 【H264解析Demo】10、变换量化_3_反变换
- vue实现浏览器代码在线编辑预览
热门文章
- 什么样的人适合参加IT编程培训?
- 百度小程序版帝国cms插件
- _snprintf_s与_snprintf
- linux http连接超时时间设置,Linux 下 HTTP连接超时
- 没有免费午餐定理No Free Lunch Theorem
- mac笔记本当做服务器记录
- bos新建工作流 服务器信息和更新端口,BOS技术支持博客 : BOS_集成消息中心开发指南...
- 【软件测试】软件测试的方法
- 使用向日葵进行远程办公,手机电脑都可以时时刻刻使用远端电脑
- Matlab 未找到支持的编译器或 SDK 解决方法归纳