赞
踩
概述:字符串是由多个字符组成的一串数据(字符序列),它可以看成是一个字符数组。Java程序中的所有字符串面值(如:“abc”)都可以看成是一个字符串对象。
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
// String底层是靠字符数组实现的。
- String类被final修饰,不可被继承
- 字符串是不可变序列,是常量,一旦被赋值,就不能被改变。(其值不能改变,但是String类型的引用所指向的地址值可以发生改变)
- 字符串字面值存放在方法区中的字符串常量池,字符串常量池中一定不存在两个相同的字符串
public static void main(String[] args) {
String name = "zhangsan";
/**
* 重新赋值时,并不是直接在原地址上覆盖zhangsan,而是在字符串池中
* 找到(创建)lisi,然后把lisi的地址赋值给name,从而实现新的赋值过程
*/
name = "lisi";
}
注意:当我们重新赋值时,并不是直接修改他的字面值,因为字面值是不可改变的,而是通过重新开辟一个空间,把新空间的地址赋值给变量,这就是不可变性
方法 | 描述 |
---|---|
String(); | 无参构造 |
String(byte[] bytes); | 把字节数组转换成字符串 |
String(byte[],int offset,int length); | 把字节数组的一部分转换成字符串 |
String(char[] value); | 把字符数组转换成字符串 |
String(char[] value,int offset,int count); | 把字符数组的一部分转换成字符串 |
String(String original); | 把字符串常量转换成字符串 |
示例:
// 直接创建
String s = "abc";// 创建一个字符串对象abc,放在方法区字符串常量池中
// 通过构造器传字符串的创建
String s1 = new String("abc");// 在堆中创建一个字符串对象,然后在常量池中找到并返回abc对象
// 通过字符数组构造
char chars[] = {'a', 'b', 'c'};
String str2 = new String(chars);// 在堆中创建一个字符串对象,然后在常量池中找到并返回abc对象
// 通过字节数组构造
byte bytes[] = { 97, 98, 99 };
String str3 = new String(bytes);// 在堆中创建一个字符串对象,然后在常量池中找到并返回abc对象
注意:字符串直接赋值的方式是先到方法区的字符串常量池里面查找,如果有就直接返回,如果没有就创建并返回。
String str = “abc”;
与String str2 = new String(“abc”);
的区别
- String str = “abc”:
可能创建一个或者不创建对象
。直接到方法区的字符串常量池里面查找,如果abc
在字符串池中存在, str直接指向这个内存地址;如果abc
在字符串池中不存在,会在java字符串池中创建一个String对象abc
,然后str指向这个内存地址,无论以后用这种方式创建多少个值为abc
的字符串对象,始终指向的都是该内存地址,即以""
方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一 个 String 对象,并在字符串池中维护。- String str = new String(“abc”):
至少会创建一个对象,也有可能创建两个
。因为用到new
关键字,肯定会在堆中创建一个String对象,如果字符池中已经存在abc
,则不会再字符串池中创建一个String对象,如果不存在,则会在字符串常量池中也创建一个对象。
方法名 | 描述 |
---|---|
int length() | 返回字符串的长度 |
char charAt(int index) | 根据下标获取字符 |
int indexOf(String str) | 查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1 |
int indexOf(int ch,int fromIndex); | 查找指定字符在指定位置后第一次出现处的索引 |
int indexOf(String str,int fromIndex); | 查找指定字符串在指定位置后第一次出现处的索引 |
char[] toCharArray() | 将字符串转换成数组。 |
byte[] getBytes(); | 把字符串转换为字节数组 |
static String valueOf(...); | String类的valueOf方法可以把任意类型的数据转换为字符串 |
String trim() | 去掉字符串前后的空格 |
String toLowerCase(); | 把字符串转换为小写 |
String toUpperCase() | 把字符串转换为大写 |
String replace(String oldString,String newString) | 把字符串中的子字符串替换为新的子字符串,原字符串不变 |
String[] split(String str) | 根据str做拆分,如空格符或给定正则表达式的匹配拆分此字符串 |
String concat(String str); | 把字符串进行拼接 |
String subString(int beginIndex,int endIndex) | 在字符串中截取出一个子字符串,范围[beginIndex,endIndex) ,包含开始,不含结束 |
boolean equals(Object obj); | 比较字符串的内容是否相同,区分大小写 |
boolean equalsIgnoreCase(String str); | 比较字符串的内容是否相同,忽略大小写 |
int compareTo(String str); | 按字典顺序比较两个字符串 |
boolean contains(String str) | 判断当前字符串中是否包含str |
boolean startsWith(String str); | 判断字符串是否以某个指定的字符串开头 |
boolean endsWith(String str) | 判断字符串是否以str结尾 |
boolean isEmpty(); | 判断字符串内容是否为空 |
native String intern(); | 直接指向常量池 |
new String()的一些参考:
演示:
System.out.println("---------字符串方法的使用 1-------------"); //字符串方法的使用 //1、length();返回字符串的长度 //2、charAt(int index);返回某个位置的字符 //3、contains(String str);判断是否包含某个子字符串 String content = "java是世界上最好的java编程语言,java真香"; System.out.println(content.length()); // 26 System.out.println(content.charAt(content.length() - 1)); // 香 System.out.println(content.contains("java")); // true System.out.println(content.contains("php")); // false System.out.println("--------字符串方法的使用 2--------------"); //字符串方法的使用 //4、toCharArray();返回字符串对应的数组 //5、indexOf();返回子字符串首次出现的位置 //6、lastIndexOf();返回字符串最后一次出现的位置 System.out.println(Arrays.toString(content.toCharArray())); System.out.println(content.indexOf("java")); // 0 System.out.println(content.indexOf("java", 4)); // 11 System.out.println(content.lastIndexOf("java"));// 20 System.out.println("------------字符串方法的使用3------------------"); //7、trim();去掉字符串前后的空格 //8、toUpperCase();//把小写转成大写 toLowerCase();把大写转成小写 //9、endWith(str);判断是否已str结尾,startWith(str);判断是否已str开头 String content2 = " hello World "; System.out.println(content2.trim()); // hello World System.out.println(content2.toUpperCase()); // HELLO WORLD System.out.println(content2.toLowerCase()); // hello world String filename = "hello.java"; System.out.println(filename.endsWith(".java")); // true System.out.println(filename.startsWith("hello")); // true System.out.println("------------字符串方法的使用4------------------"); //10、replace(char old,char new); 用新的字符或字符串替换旧的字符或字符串 //11、split();对字符串进行拆分 //12、S.substring(开始,结束) 截取某段字符 System.out.println(content.replace("java", "php")); String s = "java is the best, programing language"; System.out.println(s.substring(5,16)); // is the best // 根据空格分隔字符串 String[] arr = s.split(" "); for (String i : arr) { System.out.println(i); } System.out.println("---------------"); // 根据空格和逗号分隔,中括号表示选择,可以选择空格或逗号分隔 String[] arr2 = s.split("[ ,]"); for (String i : arr2) { System.out.println(i); } System.out.println("---------------"); /** * 根据空格和逗号分隔,中括号表示选择,可以选择空格或逗号分隔, * +号表示可以出现多个空格或逗号 */ String[] arr3 = s.split("[ ,]+"); for (String i : arr3) { System.out.println(i); } //补充两个方法equals 、compareTo();比较大小 System.out.println("---------补充---------"); String s1 = "hello"; String s2 = "HELLO"; System.out.println(s1.equalsIgnoreCase(s2)); String s3 = "abc";//97 String s4 = "ayzawe";//120 System.out.println(s3.compareTo(s4)); String s5 = "abc"; String s6 = "abc"; System.out.println(s5.compareTo(s6));
/**
* intern:先用equals方法判断字符串常量池中是否存在指定字符串,存在则直接返回常量
* 池中的字符串地址,如果字符串池中没有该字符串,则创建一个然后返回地址
* 即:无论过程多么复杂,intern方法最终返回的一定是字符串常量池中的字符串地址
*/
String s1 = "a";
String s2 = new String("a");
System.out.println(s1 == s2);// false
System.out.println(s1 == s2.intern());// true
System.out.println(s2 == s2.intern());// false
System.out.println(s1 == s1.intern());// true
注意内容为空与字符串为空的区别:
字符串内容为空:String str = "";
字符串对象为空:String str = null;(对象为空,无法调用方法:空指针异常)
重要规则:常量相加,发生在常量池中;变量相加,发生在堆中
如果两个字符串变量相加,先开辟空间,再做拼接。
- 如果
两个字符串常量相加,先做拼接
,然后在字符串常量池里面查找,如果有就直接返回,如果没有就创建并返回
String a = "hello";
String b = "World";
String s = "hello" + "World";//常量相加,直接在常量池中创建对象
String s1 = a + b; // 变量相加,要先在堆中运算,最后在常量池中创建字符串对象
String s2 = a.concat(b); // 变量相加,要先在堆中运算,最后在常量池中创建字符串对象
a += "World";// 变量相加,要先在堆中运算,最后在常量池中创建字符串对象
使用各包装类的
parseXxx()
静态方法,但是在使用时要注意字符串必须是纯数字
String i = "150";
System.out.println(Integer.parseInt(i)); // 150
String i = "150s";
System.out.println(Integer.parseInt(i));//Exception in thread "main" java.lang.NumberFormatException: For input string: "150s"//数字格式化错误,150s中含有非数字字符
字符串转换成boolean类型时,true就是true,非true为false
public static void main(String[] args) {
String i = "true";//为true
System.out.println(Boolean.parseBoolean(i));//true
String i1 = "false";//为false
System.out.println(Boolean.parseBoolean(i1));//false
String i2 = "ksajd";//非true
System.out.println(Boolean.parseBoolean(i2));//false
}
- 比较基本数据类型:比较的是具体的值
- 比较引用数据类型:比较的是对象地址值(相当于把
对象地址
当做值来比较)
Object.equals()
的实现方式也是==
,但是String重写了equals方法,所以是比较两个字符串内容是否相同(区分大小写)
public class Test { public static void main(String[] args) { String s = "a"; String s1 = "a"; String s2 = "A"; System.out.println(s.equals(s1));// true System.out.println(s2.equals(s1)); // false /** * p1.name.equals(p2.name):由于String类重写了equals方法,所以比较的是内容 * p1.name == p2.name:虽然在堆中是两个对象地址,但是p1.name与p2.name指向 * 的字符串都存储在字符串常量池中,所以返回相同的地址 * p1.name == "张三":p2.name指向的就是字符串常量池中的张三 */ Person p1 = new Person(); p1.name = "张三"; Person p2 = new Person(); p2.name = "张三"; System.out.println(p1.name.equals(p2.name)); // true System.out.println(p1.name == p2.name); // true System.out.println(p1.name == "张三"); // true } } class Person { String name; }
- 相同点:equals的实现也是==,即如果不重写equals方法,它与 == 的结果一致
- 不同点:
1)== 可以比较基本数据类型和引用类型,equals方法只能比较引用数据类型
2)== 比较的是内存地址,equals方法经过重写之后比较的是内存空间中的内容
1、键盘录入一个字符,统计字符串中大小写字母及数字字符个数
//键盘录入一个字符串数据 Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串数据:"); String s = sc.nextLine(); //定义三个统计变量,初始化值都是0 int bigCount = 0; int smallCount = 0; int numberCount = 0; //遍历字符串,得到每一个字符 for(int x=0; x<s.length(); x++) { char ch = s.charAt(x); //拿字符进行判断 if(ch>='A'&&ch<='Z') { bigCount++; }else if(ch>='a'&&ch<='z') { smallCount++; }else if(ch>='0'&&ch<='9') { numberCount++; }else { System.out.println("该字符"+ch+"非法"); } } //输出结果 System.out.println("大写字符:"+bigCount+"个"); System.out.println("小写字符:"+smallCount+"个"); System.out.println("数字字符:"+numberCount+"个");
2、已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
import java.util.Scanner; /* 思路: 1:已知用户名和密码,定义两个字符串表示即可 2:键盘录入要登录的用户名和密码,用 Scanner 实现 3:拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。字符串的内容比较,用 equals() 方法实现 4:用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环 */ public class Test { public static void main(String[] args) { //已知用户名和密码,定义两个字符串表示即可 String username = "tom"; String pwd = "123"; //用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环 for (int i = 0; i < 3; i++) { //键盘录入要登录的用户名和密码,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String name = sc.nextLine(); System.out.println("请输入密码:"); String pwd = sc.nextLine(); //拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。字符串的内容比较, if (name.equals(username) && pwd.equals(pwd)) { System.out.println("登录成功"); break; } else { if (2 - i == 0) { System.out.println("你的账户被锁定,请与管理员联系"); } else { //2,1,0 //i,0,1,2 System.out.println("登录失败,你还有" + (2 - i) + "次机会"); } } } } }
3、键盘录入一个字符串,使用程序实现在控制台遍历该字符串
import java.util.Scanner; /* 思路: 1:键盘录入一个字符串,用 Scanner 实现 2:遍历字符串,首先要能够获取到字符串中的每一个字符 public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的 3:遍历字符串,其次要能够获取到字符串的长度 public int length():返回此字符串的长度 数组的长度:数组名.length 字符串的长度:字符串对象.length() 4:遍历字符串的通用格式 */ public class Test { public static void main(String[] args) { //键盘录入一个字符串,用 Scanner 实现 Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串:"); String line = sc.nextLine(); for(int i=0; i<line.length(); i++) { System.out.println(line.charAt(i)); } } }
/**
* 一开始,s指向hello,所以在字符串池中创建了一个hello对象
* 将s的指向改为hi,此时又在池中创建了一个hi对象,所以创建了两个对象
*/
String s = "hello";
s = "hi";
/**
* 创建了一个对象
* 两个常量相加,编译器会做出优化:由于编译器会判断创建出来的
* 对象是否有引用指向,为了节约空间,编译器不允许创建垃圾对象,
* 所以会在底层做出优化,即将多步合成一步,这将避免空间浪费,所
* 以 String s = "hello" + " zhangsan";
* 等价于 String s = "hello zhangsan";
*/
String s = "hello" + "zhangsan";
String s = "hello";// 创建了一个hello对象
String s1 = "zhangsan"; // 创建了一个zhangsan对象
/**
* 在jdk1.8中:
* 1、首先创建一个StringBuilder对象st
* 2、调用append方法将hello对象添加到st对象:st.append("hello");
* 3、调用append方法将zhangsan对象添加到st对象:st.append("zhangsan");
* 4、调用st的toString方法,将StringBuilder类型转换为String类型
* 5、将结果返回给s2
* 所以,s2最终直接指向的是堆中的String对象,而不是常量池中的hellozhangsan对象
* 创建了3个对象:hello、zhangsan、hellozhangsan
*/
String s2 = s + s1;
注意:上述是在JDK1.8中的创建过程,JDK17中有所不同
public static void main(String[] args) { String s = "hello"; s += "World"; System.out.println(s); } 过程分析: // 首先跳转DirectMethodHandle.internalMemberName(Object mh) static Object internalMemberName(Object mh) { return ((DirectMethodHandle)mh).member; } // 再跳转首先跳转DirectMethodHandle$Holder.invokeStatic(Object var0, Object var1, Object var2) static Object invokeStatic(Object var0, Object var1, Object var2) { Object var3 = DirectMethodHandle.internalMemberName(var0); return MethodHandle.linkToStatic(var1, var2, (MemberName)var3); } // 再跳转StringConcatHolder.simpleConcat(Object first, Object second) static String simpleConcat(Object first, Object second) { String s1 = stringOf(first); // first = "hello" /* static String stringOf(Object value) { String s; //判断传入的第一个参数是否为null,不为null返回该字符串,即 "hello" //若第一个参数为null,则将null转换为字符串并返回,即返回 "null" return (value == null || (s = value.toString()) == null) ? "null" : s; } */ String s2 = stringOf(second); // second = "world" // 判断是否为空字符串,即 "",注意空字符串 "" 与 null的区别 if (s1.isEmpty()) { // 创建第二个参数为字符串对象 return new String(s2); } if (s2.isEmpty()) { // 创建第一个参数为字符串对象 return new String(s1); } // long indexCoder = mix(initialCoder(), s1); //获取第一个参数的长度 s1 = "hello" /* // String.COMPACT_STRINGS = true // LATIN1 = 0 static long initialCoder() { return String.COMPACT_STRINGS ? LATIN1 : UTF16; } */ /* static long mix(long lengthCoder, String value) { // 获取字符串长度 lengthCoder += value.length(); if (value.coder() == String.UTF16) { /* //COMPACT_STRINGS = true // coder = 0 byte coder() { // 确定编码长度 return COMPACT_STRINGS ? coder : UTF16; } */ lengthCoder |= UTF16; } return checkOverflow(lengthCoder); // 检查是否溢出 /* private static long checkOverflow(long lengthCoder) { if ((int)lengthCoder >= 0) { return lengthCoder; // 返回字符串长度 } throw new OutOfMemoryError("Overflow: String length out of range"); } */ } */ indexCoder = mix(indexCoder, s2);// 加上第二个参数的长度 byte[] buf = newArray(indexCoder); // 创建一个新的数组 /* static byte[] newArray(long indexCoder) { byte coder = (byte)(indexCoder >> 32); int index = (int)indexCoder; return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); } */ indexCoder = prepend(indexCoder, buf, s2); /* private static long prepend(long indexCoder, byte[] buf, String value) { indexCoder -= value.length(); // 10 - 5 if (indexCoder < UTF16) { value.getBytes(buf, (int)indexCoder, String.LATIN1); /* void getBytes(byte[] dst, int dstBegin, byte coder) { if (coder() == coder) { System.arraycopy(value, 0, dst, dstBegin << coder, value.length); } else { // this.coder == LATIN && coder == UTF16 StringLatin1.inflate(value, 0, dst, dstBegin, value.length); } } */ } else { value.getBytes(buf, (int)indexCoder, String.UTF16); } return indexCoder; } */ indexCoder = prepend(indexCoder, buf, s1); return newString(buf, indexCoder); /* static String newString(byte[] buf, long indexCoder) { // Use the private, non-copying constructor (unsafe!) if (indexCoder == LATIN1) { return new String(buf, String.LATIN1); } else if (indexCoder == UTF16) { return new String(buf, String.UTF16); } else { throw new InternalError("Storage is not completely initialized, " + (int)indexCoder + " bytes left"); } } */ }
概述:每次对字符串进行拼接操作,都会构建一个新的String对象,既耗时又浪费空间,而可变字符串就可以解决这个问题。
由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。例如:
public class StringDemo {
public static void main(String[] args) {
String s = "Hello";
s += "World";
System.out.println(s);
}
}
在API中对String类有这样的描述:字符串是常量,它们的值在创建后不能被更改
。
根据这句话分析我们的代码,其实总共产生了三个字符串,即"Hello"
、"World"
和"HelloWorld"
。引用变量s首先指向Hello
对象,最终指向拼接出来的新字符串对象,即HelloWord
。由此可知,如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为了解决这一问题,可以使用可变字符串
类。
可变字符串分为
java.lang.StringBuffer
类和java.lang.StringBuilder
类
StringBuilder
与StringBuffer
的直接父类是AbstractStringBuilder
,而且他们的数据也是存放在AbstractStringBuilder
类中的char[] value
数组中,这里的value
数组没有使用final
修饰,且value的值是存放在堆中的,所以StringBuffer和StringBiulder才是可变的,注意:StringBuffer和StringBiulder都是final修饰的类,所以不可继承
概念:可变长字符串,JDK1.0提供,运行效率慢、线程安全。可在内存中创建可变的缓冲空间,存储频繁改变的字符串,线程安全的可变字符序列。
其所有成员方法都使用synchronized关键字修饰,所以是线程安全的
//private final char value[];
//char[] value; 这个放在堆.
public StringBuffer();
无参构造方法,其初始容量为 16 个字符
public StringBuffer(int capacity);
指定容量的字符串缓冲区对象
public StringBuffer(String str);
指定字符串内容的字符串缓冲区对象
int capacity();
返回当前容量 – 理论值
int length();
返回长度(字符数) – 实际值
StringBuffer append(String str);
把字符串添加到字符串缓冲区,并返回字符串缓冲区本身注意:该方法被多次重载,可以把任意类型的数据添加到字符串缓冲区
StringBuffer insert(int offset,String str);
在指定位置把字符串插入到字符串缓冲区,并返回本身注意:该方法被多次重载,可以在指定位置把任意类型的数据插入到字符串缓冲区
public StringBuffer deleteCharAt(int index);
删除指定位置的字符,并返回本身
public StringBuffer delete(int start,int end);
删除从指定位置开始到指定位置结束的内容,并返回本身注意:包含start,但是不包含end
public StringBuffer replace(int start,int end,String str);
从start开始到end结束用str替换,并返回本身public void setCharAt(int index,char ch);
将给定索引处的字符设置为ch
public StringBuffer reverse();
- public String substring(int star);
- public String substring(int star,int end);
注意:截取功能和前面的几个功能有所不同,其返回值是String类型,但本身并没有发生改变,即字符串本身并没有
String a = "hello World !";
String s = a.substring(5, a.length() - 1);
System.out.println("原字符串:" + a); // 原字符串:hello World
System.out.println("截取的字符串:" + s); //截取的字符串: World
- 构造方法:public StringBuffer(String str);
//返回才是StringBuffer对象,str不变
- append方法:public StringBuffer append(String str);
构造方法:public String(StringBuffer sb);
toString方法:public String toString();
备注:StringBuilder已经覆盖重写了Object当中的toString方法。
两者都可以看作是一个容器,用来放置数据:
- StringBuffer的数据最终是一个字符串数据
- 数组可以放置多种类型的数据,但同一个数组中的数据必须是同一类型的
- String是常量值,一种特殊的引用类型,当它作为参数传递时,效果和基本数据类型作为参数传递一样
- StringBuffer作为参数传递,当它用来调用方法时,其形式参数的改变直接影响实际参数的改变
可变长字符串,JDK5.0提供,运行效率快、线程不安全,其方法和属性与StringBuffer几乎完全一致,只是没有使用
synchronized
关键字修饰,java.lang.StringBuilder
是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。它的内部拥有一个数组用来存放字符串内容,进行字符串拼接时,直接在数组中加入新内容。StringBuilder会自动维护数组的扩容。默认16字符空间,超过自动扩充
字符串缓冲区被单个线程使用的时候
,即单个线程的时候使用StringBuilder效率较高,多个线程的时候使用StringBuffer比较安全
线程安全(多线程内容)
安全 -- 同步 -- 数据是安全的
不安全 -- 不同步 -- 效率高一些
安全和效率两者不可兼得,需要根据需求有所取舍:
安全:银行网站,医院网站
效率:新闻网站,论坛
(1)String的内容和长度都是不可变的,而StringBuffer和StringBuilder的内容和长度都是可变的
(2)StringBuffer是同步的,数据安全,但效率低;而StringBuilder是不同步的,效率高,但不安全(多线程情况)
注意:
StringBuilder和StringBuffer没有重写Object的equals方法
二者的方法基本相同,StringBuilder线程不安全,但是效率高,StringBuffer线程安全,效率低,单线程使用StringBuilder,他们都比String效率高,比较节省内存
public class TestStringBuilder { public static void main(String[] args) { /** * 测试String类与StringBuilder的效率 */ StringBuilder str = new StringBuilder("abc"); String str1 = new String("abc"); /** * 测试string与StringBuilder的效率 */ long r = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间 long time = System.currentTimeMillis();//获取当前系统时间 //测试string for (int i = 0; i < 500; i++) { str1 = str1 + i; //System.out.println(str1.hashCode()); } long r1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间 long time1 = System.currentTimeMillis();//获取当前系统时间 System.out.println("运行时间:" + (time1 - time)); System.out.println("占用空间:" + (r - r1)); long r3 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间 long time3 = System.currentTimeMillis();//获取当前系统时间 //测试StringBuilder for (int i = 0; i < 500; i++) { str.append(i); //System.out.println(str.hashCode()); } long r4 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间 long time4 = System.currentTimeMillis();//获取当前系统时间 System.out.println("运行时间:" + (time4 - time3)); System.out.println("占用空间:" + (r3 - r4)); } }
连续调用。该方法的核心是调用了return this,把自己返回了,只要是返回自己,就可以连续调用
StringBuilder str = new StringBuilder();
str.insert(0, "张").insert(1, "三").reverse().reverse();
System.out.println(str);//输出三张
public StringBuilder reverse() { // 反转字符串
super.reverse();
return this;//返回自己
}
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);//在指定位置插入字符串
return this;//返回自己
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。