String 类
概述
String类代表字符串,使用一对 “” 引起来,Java程序中的所有字符串字面值(如”abc”)都作为此类的实例实现
- String声明为final的,不可被继承
- String实现了Serializable接口:表示字符串是支持序列化的
- String实现了Comparable接口:表示String可以比较大小
- String内部定义了final char[] value用于存储字符串数据
- String代表不可变的字符序列。简称:不可变性
- 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
字符串常量池中是不会存储相同内容的字符串的
public final class String
implements 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的不可变性
体现
当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
- 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
- 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值 ```java String s1 = “abc”; // 字面量的定义方式 String s2 = “abc”; System.out.println(s1 == s2); // true 比较s1和s2的地址值
s1 = “hello”; System.out.println(s1 == s2); // false System.out.println(s1); // hello System.out.println(s2); // abc
System.out.println(“*“);
String s3 = “abc”; s3 += “def”; System.out.println(s3); // abcdef System.out.println(s2);
System.out.println(“*“);
String s4 = “abc”; String s5 = s4.replace(‘a’, ‘m’); System.out.println(s4); // abc System.out.println(s5); // mbc
<br />**为什么String要设计成不可变的**
- 运行时常量池的需要
多个相同的String共用一个对象,若是可以修改,会导致其他引用同时改变
- 同步
- 允许String对象缓存hashcode
字符串不变性保证了hash码的唯一性
- 安全性
String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,<br />还有反射机制所需要的String参数等,假若String不是固定不变的,将会引起各种安全隐患
<a name="f01d80f10f60e7e74884f79092521223"></a>
#### String实例化方式说明
方式一:通过字面量定义的方式<br />方式二:通过new + 构造器的方式
```java
//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // false
System.out.println(s3 == s4); // false
System.out.println("***********************");
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);
System.out.println(p1.name.equals(p2.name)); // true
System.out.println(p1.name == p2.name); // true
p1.name = "Jerry";
System.out.println(p2.name); // Tom
面试题
String s = new String(“abc”); 方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:”abc”
String str1=“abc”; 与 String str2= new String(“abc”); 的区别
字符串拼接方式赋值对比
说明
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量
- 只要其中一个是变量,结果就在堆中
- 如果拼接的结果调用intern()方法,返回值就在常量池中
- 调用 “ab”.intern()方法的时候会返回 “ab”,但是这个方法会首先检查字符串池中是否有 “ab”这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用 ```java 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(); // 返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
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
```java
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3); // false
final String s4 = "javaEE"; // s4:字符常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5); // true
String使用陷阱
1. String s1 = "a";
在字符串常量池中创建了一个字面量为 "a" 的字符串
2. s1 = s1 + "b"
实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1 + "b"(也就是 "ab")。
如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。
如果这样的操作放到循环中,会极大影响程序的性能
3. String s2 = "ab";
4. String s3 = "a" + "b";
s3指向字符串常量池中已经创建的 "ab" 的字符串。
5. String s4 = s1.intern();
堆空间的S1对象在调用 intern () 之后,会将常量池中已经存在的 "ab" 字符串赋值给s4
//一道面试题
public class StringTest {
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.println(ex.str); // good
System.out.println(ex.ch); // best
}
}
JVM中涉及字符串的内存结构
- jdk 1.6:字符串常量池存储在方法区(永久区)
- jdk 1.7:字符串常量池存储在堆空间
- jdk 1.8:字符串常量池存储在方法区(元空间)
构造器
**public String()**
**public String(String original)**
字节数组转字符串**public String(byte[] bytes)**
注意字节数组的格式,数值范围-128~127**public String(byte[] bytes, int offset, int length, String charsetName)**
字符数组转字符串**public String(char[] value)**
**public String(char[] value, int offset, int count)**
其他**public String(StringBuffer buffer)**
**public String(StringBuilder builder)**
方法
String类的判断功能**boolean equals(Object obj)**
比较字符串的内容是否相同,区分大小写**boolean equalsIgnoreCase(String str)**
比较字符串的内容是否相同,忽略大小写**boolean contains(String str)**
判断大字符串中是否包含小字符串**boolean startsWith(String str)**
判断字符串是否以某个指定的字符串开头**boolean startsWith(String str int toffset)**
从指定索引位置以指定前缀开始**boolean endsWith(String str)**
判断字符串是否以某个指定的字符串结尾**boolean isEmpty()**
判断字符串是否为空
String类的获取功能**public int length()**
返回此字符串的长度**char charAt(int index)**
获取指定索引位置的字符
索引**int indexOf(int ch)**
返回指定字符在此字符串中第一次出现处的索引,没有返回-1**int indexOf(int ch, int fromIndex)**
返回指定字符在此字符串中从指定位置后第一次出现处的索引**int indexOf(String str)**
返回指定字符串在此字符串中第一次出现处的索引**int indexOf(String str, int fromIndex)**
返回指定字符串在此字符串中从指定位置后第一次出现处的索引**int lastIndexOf(String str)**
返回指定子字符串在此字符串中最右边出现处的索引**int lastIndexOf(String str, int fromIndex)**
获取子串**String substring(int start)**
从指定位置开始默认到末尾包含start这个索引**String substring(int start, int end)**
从指定位置开始到指定位置结束截取字符串。包括start索引但是不包end索引
String的转换功能**byte[] getBytes()**
把字符串转换为字节数组**char[] toCharArray()**
把字符串转换为字符数组**void getChars(char dst[], int dstBegin)**
**static String valueOf(char[] chs)**
把字符数组转成字符串**static String valueOf(Object i)**
把其他类型的数据转成字符串
注意:String类的valueOf方法可以把任意类型的数据转成字符串**String toLowerCase()**
把字符串转成小写**String toUpperCase()**
把字符串转成大写
String的替换功能**String replace(char old, char new)**
将字符串中的一个字符替换成另一个字符**String replace(String old, String new)**
将一个小字符串替换成另一个字符串**String replaceAll(String regex, String replacement)**
使用给定的replacement 替换此字符串所匹配给定的正则表达式的子字符串**String replaceFirst(String regex, String replacement)**
替换第一个子字符串
String类的其他功能**String trim()**
去除字符串两端空格 (只可以去除前后不能去除中间的空格)**boolean matches(String regex)**
告知此字符串是否匹配给定的正则表达式**String concat(String str)**
将指定字符串连接到此字符串的结尾。 等价于用“+”
按字典顺序比较两个字符串 **int compareTo(String str)**
先比对应位置的字符的差,都相同再比长度差**int compareToIgnoreCase(String str)**
拆分**String[] split(String regex)**
根据匹配给定的正则表达式来拆分此字符串,**String[] split(String regex, int limit)**
最多不超过limit个,如果超过剩下的全部都放到最后一个元素中
String s1 = "helloworld";
System.out.println(s1.length()); // 10
System.out.println(s1.charAt(4)); // o
System.out.println(s1.isEmpty()); // false
String s2 = "HelloWorld";
System.out.println(s2.toLowerCase()); // helloworld
System.out.println(s2.toUpperCase()); // HELLOWORLD
String s3 = " hello world ";
System.out.println(s3.trim()); //hello world
String s4 = "helloworld";
System.out.println(s4.equals(s1)); // true
System.out.println(s4.equalsIgnoreCase(s2)); // true
String s5 = "hello";
System.out.println(s5.compareTo(s4)); // -5 相等时返回0,小的时候返回负数
System.out.println(s4.compareTo(s1)); // 0
System.out.println(s4.substring(5)); // world
System.out.println(s4.substring(5, 9)); // worl,取值范围左闭右开
String s1 = "javaEE";
System.out.println(s1.endsWith("EE")); // true
System.out.println(s1.startsWith("a")); // false
System.out.println(s1.startsWith("EE", 4)); // true
String s2="hello word";
System.out.println(s2.contains("o")); // true
System.out.println(s2.indexOf("h")); // 0
System.out.println(s2.indexOf("o", 5)); // 7 返回的是s2中的索引
System.out.println(s2.lastIndexOf("o")); // 7
System.out.println(s2.lastIndexOf("l", 2)); // 2
System.out.println(s1.indexOf("lo"));
System.out.println(s1.indexOf("lo",5)); // 返回的还是s2中从前往后出现位置的索引
String str1 = "北京尚硅谷教育北京";
String str2 = str1.replace('北', '东');
System.out.println(str1); // 北京尚硅谷教育北京
System.out.println(str2); // 东京尚硅谷教育东京
String str3 = str1.replace("北京", "上海"); // 上海尚硅谷教育上海
System.out.println(str3);
System.out.println("*************************");
String str = "12hello34world5java7891mysql456";
// 把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉
String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string); // hello,world,java,mysql
System.out.println("*************************");
str = "12345";
// 判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str.matches("\\d+");
System.out.println(matches); // true
String tel = "0571-4534289";
// 判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result); // true
System.out.println("*************************");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (String value : strs) {
System.out.println(value);
}
System.out.println();
str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for (String s : strs2) {
System.out.println(s);
}
String与其他结构的转换
String与基本数据类型、包装类之间的转换
String—>基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)也可以Xxx.valueOf()
基本数据类型、包装类—>String:调用String重载的valueOf(xxx)
String str1 = "123";
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num); // "123"
String str3 = num + "";
System.out.println(str1 == str3);
与字符数组之间的转换
String —> char[]:调用String的toCharArray() / getChars()
char[] —> String:调用String的构造器
String str1 = "abc123"; //题目:a21cb3
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
与字节数组之间的转换
String —> byte[]:调用String的getBytes()
byte[]—> String:调用String的构造器
编码:字符串—>字节 (看得懂的数据—->二进制数据)
解码:编码的逆过程,字节—>字符串(二进制数据 —->看得懂的数据)
说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码
public void test() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes(); // 使用默认的字符集,进行编码。
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk"); // 使用gbk字符集进行编码。
System.out.println(Arrays.toString(gbks));
String str2 = new String(bytes); // 使用默认的字符集,进行解码。
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3); // 出现乱码。原因:编码集和解码集不一致!
String str4 = new String(gbks, "gbk");
System.out.println(str4); // 没有出现乱码。原因:编码集和解码集一致!
}
与StringBuffer、StringBuilder之间的转换
String —>StringBuffer、StringBuilder:
- 调用new 构造器
- append()方法 ```java String str1 =”helloword”; StringBuffer stringBuffer = new StringBuffer(str1); System.out.println(stringBuffer); // helloword StringBuilder stringBuilder = new StringBuilder(str1); System.out.println(stringBuilder); // helloword
stringBuffer.append(“isStringBuffer”); System.out.println(stringBuffer); stringBuilder.append(“isStringBuider”); System.out.println(stringBuilder);
StringBuffer、StringBuilder -->String:
- 调用String构造器
- StringBuffer、StringBuilder的 `**toString()**`
```java
StringBuffer sb1 = new StringBuffer("hello StringBuffer");
StringBuilder sb2 = new StringBuilder("hello StringBuider");
System.out.println(new String(sb1));
System.out.println(new String(sb2));
System.out.println(sb1.toString());
System.out.println(sb2.toString());
常见算法题目的考查
模拟一个trim方法,去除字符串两端的空格
public String myTrim(String str) {
if (str != null) {
int start = 0; // 记录从前往后首次索引位置不是空格的位置索引
int end = str.length() - 1; // 记录从后往前首次索引位置不是空格的位置索引
while (start < end && str.charAt(start) == ' ') {
start++;
}
while (start < end && str.charAt(end) == ' ') {
end--;
}
if (str.charAt(start) == ' ') {
return "";
}
return str.substring(start, end + 1);
}
return null;
}
将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg”
// 方式一
public String reverse1(String str, int start, int end) {
if (str != null) {
// 1.转换成char型数组
char[] charArray = str.toCharArray();
// 2.进行反转操作
for (int i = start, j = end; i < j; i++, j--) {
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
}
//3.返回值
return new String(charArray);
}
return null;
}
// 方式二
// 分析:整个字符串分为三部分不反转的、反转的、不反转的
// 先将前面不反转的部分取出来,将反转的部分取出后进行拼接
public String reverse2(String string, int start, int end) {
if(string != null){
//第一部分
String newStr = string.substring(0, start);
//第二部分
for (int i = end; i >= start; i--) {
newStr += string.charAt(i);
}
//第三部分
newStr += string.substring(end + 1);
//拼接操作
return newStr;
}
return null;
}
//方式三,使用StringBuffer或StringBuilder替换String优化
public String reverse3(String str, int start, int end) {
if(str != null){
//1.新建StringBuffer
StringBuffer stringBuffer = new StringBuffer(str.length());
//2.第一部分
stringBuffer.append(str.substring(0, start));
//3.第二部分
for (int i = end; i >= start; i--) {
stringBuffer.append(str.charAt(i));
}
//4.第三部分
stringBuffer.append(str.substring(end + 1));
//5.拼接操作
return stringBuffer.toString();
}
return null;
}
获取一个字符串在另一个字符串中出现的次数
比如:获取“ ab”在 “abkkcadkabkebfkabkskab” 中出现的次数
public int count(String mainStr, String subStr) {
// 1.判断主串和部分串的大小
if (mainStr.length() >= subStr.length()) {
int index = 0;
int count = 0;
//2.在主串中取出子串下标,并将新的下标赋值给主串,统计量加1
// while ((index = mainStr.indexOf(subStr) )!= -1){
// count++;
// //从已经找到的子串的下一个开始
// mainStr = mainStr.substring(index + subStr.length());
// }
//改进,不再新建字符串,只做位置比对
while ((index = mainStr.indexOf(subStr, index)) != -1) {
index += subStr.length();
count++;
}
return count;
} else {
return 0;
}
}
获取两个字符串中最大相同子串
比如:str1 = “abcwerthelloyuiodef“;str2 = “cvhellobnm”
提示:将短的那个串进行长度依次递减的子串与较长的串比较
// 只存在一个子串的情况
public String getMaxSameSubString(String str1, String str2) {
// 1.判断两个字串的大小
if (str1 != null && str2 != null) {
String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
String minStr = (str1.length() < str2.length()) ? str1 : str2;
int len = minStr.length();
// 2.用小的依次去比对大的子串
for (int i = 0; i < len; i++) { //这层for循环用来确定需要比对的字符次数
for (int x = 0, y = len - i; y <= len; x++, y++) {
if (maxStr.contains(minStr.substring(x, y))) {
return minStr.substring(x, y);
}
}
}
}
return null;
}
//存在多个相同子串的情况
// 此时先返回String[],后面可以用集合中的ArrayList替换,较方便
public String[] getMaxSameSubStrings(String str1, String str2) {
// 1.先比较出两个子串的大小
if (str1 != null && str2 != null) {
StringBuffer stringBuffer = new StringBuffer();
String maxStr = (str1.length() > str2.length()) ? str1 : str2;
String minStr = (str1.length() > str2.length()) ? str2 : str1;
// 2.用小的去依次匹配大的
int len = minStr.length();
for (int i = 0; i < len; i++) {
for (int x = 0, y = len - i; y <= len; x++,y++ ){
String subString = minStr.substring(x,y);
// 3.取出匹配到的子串
if (maxStr.contains(subString)){
stringBuffer.append(subString+",");
}
}
//System.out.println(stringBuffer);
if (stringBuffer.length() != 0){
break;
}
}
String [] split = stringBuffer.toString().replaceAll(",$","").split("\\,");
return split;
}
return null;
}
对字符串中字符进行自然顺序排序。 提示:
- 字符串变成字符数组
- 对数组排序,择,冒泡,Arrays.sort();
- 将排序后的数组变成字符串
@Test
public void charTest() {
String str1 = "hello java";
char[] charArray = str1.toCharArray();
Arrays.sort(charArray);
String str2 = new String(charArray);
System.out.println(str2);
}
StringBuffer 类
概述
java.lang.String.Buffer代表可变的字符序列,JDK1.0中声明,
- 是线程安全的可变字符串
- 可以对字符串内容进行增删,此时不会产生新的对象
- 很多方法与String相同 作为参数传递时,方法内部可以改变值
StringBuffer类不同于 String,其对象必须使用构造器生成
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value; //value没有final声明,value可以不断扩容
/**
* The count is the number of characters used.
*/
int count; //count记录有效字符个数
构造器
**StringBuffer()**
初始容量为16的字符串缓冲区**StringBuffer(int size)**
构造指定容量的字符串缓冲区**StringBuffer(String str)**
将内容初始化为指定字符串内容String s = new String("我喜欢学习");
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer. append("数学");
方法**public int capacity()**
返回当前容量。理论值(水杯最多可以装多少水)**public int length()**
返回长度(字符数)。实际值(实际上水杯有多少水)添加功能
**public StringBuffer append(String str)**
可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身**public StringBuffer insert(int offset,String str)**
在指定位置插入xxx
- 删除功能
**public StringBuffer deleteCharAt(int index)**
删除指定位置的字符,并返回本身**public StringBuffer delete(int start, int end)**
- 替换功能
**public void setCharAt(int n ,char ch)**
设置指定位置的字符**StringBuffer replace(int start, int end, String str)**
从start开始到end用str替换(包括start不包括end)
- 反转功能(Stirng类没有)
**public StringBuffer reverse()**
字符串反转
- 截取功能
**public String substring(int start)**
**public String substring(int start, int end)**
- 转换功能
**String toString()**
**public int indexOf(String str)**
返回子串的下标**public char charAt(int n)**
返回指定位置的字符
当 append和insert时,如果原来vaue数组长度不够,扩容
如上这些方法支持方法链操作。 方法链的原理
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public void stringBufferMethodTest(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(1);
s1.append('1');
System.out.println(s1);
// s1.delete(2,4);
// s1.replace(2,4,"hello");
// s1.insert(2,false);
// s1.reverse();
String s2 = s1.substring(1, 3);
System.out.println(s1);
System.out.println(s1.length());
System.out.println(s2);
}
StringBuilder 类
StringBuilder和 StringBuffer非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样,只是StringBuilder类没有加线程锁,执行效率更高
String、StringBuffer、StringBuilder三者的对比
- String:不可变的字符序列;底层使用char[]存储;占用内存(会不断的创建和回收对象)
- StringBuffer:可变的字符序列;线程安全的,效率低;线程安全;底层使用char[]存储;
- StringBuilder:可变的字符序列;jdk5.0新增,线程不安全,效率高;底层使用char[]存储
注意:作为参数传递的话,方法内部String不会改变其值, StringBuffer和 StringBuilder会改变其值
StringBuffer与StringBuilder的内存解析
以StringBuffer为例
String str = new String(); //char[] value = new char[0];
String str1 = new String("abc"); //char[] value = new char[]{'a','b','c'};
//char[] value = new char[16];底层创建了一个长度是16的数组。
StringBuffer sb1 = new StringBuffer();
System.out.println(sb1.length());
sb1.append('a'); //value[0] = 'a';
sb1.append('b'); //value[1] = 'b';
//char[] value = new char["abc".length() + 16];
StringBuffer sb2 = new StringBuffer("abc");
StringBuffer构造器源码
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
问题1. System.out.println(sb2.length()); //接上面例子,length为3
问题2. 扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组
默认情况下,扩容为原来容量的 2倍 + 2,同时将原有数组中的元素复制到新的数组中
如果扩容了还不够,就将value.length + 添加的长度作为扩容后数组长度
指导意义:开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
对比String、StringBuffer、StringBuilder三者的执行效率
从高到低排列:StringBuilder > StringBuffer > String
//初始设置
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));
IDEADebug
public class IDEADebug {
@Test
public void testStringBuffer(){
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str); // null会增加"null"
System.out.println(sb.length()); // 4
System.out.println(sb); // "null"
StringBuffer sb1 = new StringBuffer(str); // 抛异常NullPointerException
// 因为要调用str.length();
System.out.println(sb1);
}
}