一、String
Java 提供了 String 类来创建和操作字符串,在Java中也是应用最广泛的对象之一。
- String属于java.lang.String类,表示字符串,是引用数据类型。
- 在整个生命周期内是 不可变 的。(被final修饰 )
- 显式的String常量放在方法区中的常量池,String对象放在堆中。
存储位置
String str = "1";
//String: 存储在堆中
//str :存储在栈中
//"1":存储在常量池中
String的优化过程
1. 在Java6及以前版本中
- String是对char数组进行了封装实现的对象,主要的成员变量有四个:数组(char)、偏移量 (offset)、字符数量 (count)、哈希值 (hash)。
- String是通过offset 和 count 两个属性来定位 char[] 数组,获取字符串。这么做可以高效、快速地共享数组对象,同时节省内存空间,但这种方式很有可能会导致内存泄漏。
2.在Java7到Java8
- 从Java7开始,String中不在有不再有 offset 和 count 两个变量了,使得String对象占用的内存稍微少些了。同时 String.substring 方法不在共享数组,解决了内存泄漏的问题。
3.Java9
- 将char[]数组变为了byte[],节约空间(char是两个字节,存一个字节的字符有点浪费)。
- 更新了一个新属性coder,它是编码格式的标识,在计算字符串长度或者调用 indexOf() 函数时,需要根据这个字段判断如何计算字符串长度。
coder 属性默认有 0 和 1 两个值, 0 代表Latin-1(单字节编码),1 代表 UTF-16 编码。如果 String判断字符串只包含了 Latin-1,则 coder 属性值为 0 ,反之则为 1。
String创建方式
//1.通过字符串常量的方式
String str= "Hello";
/*
使用这种形式创建字符串时, JVM 会在字符串常量池中先检查是否存在该对象,如
果存在,返回该对象的引用地址,如果不存在,则在字符串常量池中创建该字符串对
象并且返回引用。使用这种方式创建的好处是:避免了相同值的字符串重复创建,
节约了内存
*/
//2.构造函数的方式
String str = new String("Hello");
/*
编译时:
“Hello”被加入到常量结构中,类加载时候就会在常量池中创建该字符串。
new()时:
JVM调用String的的构造函数,同时引用常量池中的“Hello”字符串,在堆内存中
创建一个String对象并返回内存地址。
*/
字符串的拼接
/*字符串的拼接是对字符串操作使用最频繁的操作之一,由于知道String的不可变性,我们一般会认为在使用 + 进行字符串拼接时会生成很多无用的对象,
其实并不会。
Java对编译器是进行了优化的:*/
//创建时使用 + 拼接
String str = "He" +"ll"+"o";
/*上面的这段字符串拼接会被我们的编译器优化,优化成一个 String str = "Hello"; 对象。*/
//使用 + 动态拼接
String ss = "Hello";
for(int i=0; i<1000; i++) {
ss = ss + i;
}
//编译器会优化成:
String ss = "Hello";
for(int i=0; i<1000; i++) {
ss = (new StringBuilder(String.valueOf(ss ))).append(i).toString();
}
/*虽然每次循环都会实例一个新的StringBuilder,但是比每次新建一个String对象好很多。*/
/*我们自己在优化动态的拼接字符串时,如果不涉及到线程安全的情况下,我们显示的使用 StringBuilder 进行拼接,提升系统性能,
如果涉及到线程安全的话,我们使用 StringBuffer 来进行字符串拼接*/
String常用方法
1.//求长度
public int length()//返回该字符串的长度
2.//求字符串某一位置字符
public char charAt(int index)//返回字符串中指定位置的字符;注意字符串中第一个字符索引是0。
3.//提取字符串中的子串
public String substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回。
public String substring(int beginIndex, int endIndex)//该方法从beginIndex位置起,从当前字符串中取出到endIndex-1位置的字符作为一个新的字符串返回。
4.//字符串比较
public boolean equals(Object anotherObject)//比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false。
public boolean equalsIgnoreCase(String anotherString)//与equals方法相似,但忽略大小写。
public int compareTo(String anotherString)//该方法是对字符串内容按字典顺序进行大小比较,通过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
public int compareToIgnore(String anotherString)//与compareTo方法相似,但忽略大小写。
5.//字符串连接
public String concat(String str)//将参数中的字符串str连接到当前字符串的后面。等价使用“+“
6.//单个字符查找
public int indexOf(int ch/String str)//用于查找当前字符串中字符或子串,返回字符或子串在当前字符串中从左边起首次出现的位置,若没有出现则返回-1。
public int indexOf(int ch/String str, int fromIndex)//改方法与第一种类似,区别在于该方法从fromIndex位置向后查找。
public int lastIndexOf(int ch/String str)//该方法与第一种类似,区别在于该方法从字符串的末尾位置向前查找。
public int lastIndexOf(int ch/String str, int fromIndex)//该方法与第二种方法类似,区别于该方法从fromIndex位置向前查找。
7.//字符串中字符的大小写转换
public String toLowerCase()//返回将当前字符串中所有字符转换成小写后的新串
public String toUpperCase()//返回将当前字符串中所有字符转换成大写后的新串
8.//字符串中字符的替换
public String replace(char oldChar, char newChar)//用字符newChar替换当前字符串中所有的oldChar字符,并返回一个新的字符串。
public String replaceFirst(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的第一个和字符串regex相匹配的子串,应将新的字符串返回。
public String replaceAll(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的所有和字符串regex相匹配的子串,应将新的字符串返回。
9.//去除两端空格
String trim()//截去字符串两端的空格,但对于中间的空格不处理。
10.//判断是否以指定前缀开始
boolean startsWith(String prefix)//测试此字符串是否以指定的前缀开头。
boolean startsWith(String prefix, int toffset)//测试在指定索引处开始的此字符串的子字符串是否以指定的前缀开头。
11.//是否以指定后缀结尾
boolean endWith(String suffix)//测试此字符串是否以指定的后缀结尾。
12.//是否包含
boolean contains(String str)//判断参数s是否被包含在字符串中,并返回一个布尔类型的值。
13.//以指定内容拆分
String[] split(String str)//将str作为分隔符进行字符串分解,分解后的字字符串在字符串数组中返回。
字符串与基本类型的转换
public static byte parseByte(String s);
public static short parseShort(String s);
public static short parseInt(String s);
public static long parseLong(String s);
public static float parseFloat(String s);
public static double parseDouble(String s);
基本类型转换为字符串类型
static String valueOf(char data[])
static String valueOf(char data[], int offset, int count)//从 data[offset] 开始取 count 个元素 转换成字符串
static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(float f)
static String valueOf(double d)
二、Stringbuilder
StringBuilder继承自抽象类AbstractStringBuilder类,是一个可变的字符序列,但不保证同步。 在可能的情况下,建议优先使用StringBuilder,因为它在大多数实现中将更快。
构造函数
StringBuilder() value内容为空,并设置容量为16个字节;
StringBuilder(CharSequece seq) 使用seq初始化,容量在此基础上加16;
StringBuilder(int capacity) 设置特定容量;
StringBuilder(String str) 使用str初始化,容量str大小的基础上加16;
常用方法
1.//append方法
append();
//由于继承了Appendable接口,所以要实现append方法,StringBuilder类对几乎所有的基本类型都重载了append方法
2.//insert方法
insert();
//insert方法可以控制插入的起始位置,也几乎对所有的基本类型都重载了insert方法
3.capacity() //返回当前容量。
4.length() //返回内容的大小。
5.charAt(int index) //返回位置index处的字符
6.indexOf(String str) //返回str第一次出现的位置
7.indexOf(String str,int fromIndex) //返回从fromIndex开始str第一次出现的位置
8.lastIndexOf(String str) //返回str最后出现的位置
9. lastIndexOf(String str,int fromIndex) //返回从fromIndex开始最后一次出现str的位置
10.substring(int start) //返回start开始延伸至末尾的子串
11.substring(int start,int end) //返回start开始至end结束的子串
三、StringBuffer
StringBuffer继承了抽象类AbstractStringBuilder,在AbstractStringBuilder类中,有两个字段分别是char[]类型的value和int类型的count,也就是说,StringBuffer本质上是一个字符数组。是线程安全,可变的字符序列。 字符串缓冲区就像一个String ,但可以修改。 在任何时间点,它包含一些特定的字符序列,但可以通过某些方法调用来更改序列的长度和内容。
构造方法
StringBuffer() value内容为空,并设置容量为16个字节;
StringBuffer(CharSequece seq) 使用seq初始化,容量在此基础上加16;
StringBuffer(int capacity) 设置特定容量;
StringBuffer(String str) 使用str初始化,容量str大小的基础上加16;
常用方法(参考Stringbuilder 常用方法)
四、总结
速度上:String<StringBuffer<StringBuilder;
安全上:StringBuffer线程安全,StringBuilder线程不安全
原因:
String的每次改变都会涉及到字符数组的复制,而StringBuffer和StringBuilder直接在字符数组上改变;同时,StringBuffer是线程安全的,而StringBuilder线程不安全,没有StringBuffer的同步,所以StringBuilder快于StringBuffer。
建议:
如果对字符串的改变少,使用String;
如果对字符串修改的较多,使用Stringbuilder或者StringBuffer,使用StringBuffer线程安全,效率没有Stringbuilder快;使用Stringbuilder,效率更快,不是线程安全。可根据实际业务选择