String对象的另一种初始化方式
String() --------- 初始化一个String对象,表示一个空字符序列 String s = new String();
String(String value) --------- 利用一个直接量创建一个新串 String s1 = new String(“hello”);
String(char[] value) --------- 利用一个字符数组创建 char[] c = {'h','e','l','l','o'}; String s2 = new String(c);
String(char[] value,int offset,int count) --------- 截取字符数组,从offset开始count个字符创建 'String s3 = new String(c,1,3);
String(StringBuffer buffer) --------- 利用StringBuffer创建
equals()和==的区别
- public static void main(String[] args) {
- String s = "hello world";
- String s1 = new String("hello world");
- String s2 = new String("hello world");
- String s3 = new String("hello");
- String s4 = "hello world";
- System.out.println(s.equals(s1));; //true
- System.out.println(s1.equals(s2)); //true
- System.out.println(s1.equals(s3)); //false
- System.out.println("------------------");
- System.out.println(s == s1);
- System.out.println(s == s3);
- System.out.println(s == s4); 直接量的字符串会产生缓存池,所以,当声明s4的时候,编译器检测到缓存池中存在相同的字符串,所以就直接使用,只要将s4指向s所指向的字符串就行了,二者指向同一字符串,所以地址当然相等
- }
常用方法
public char charAt(int index)-----------
获取指定位置的字符
indexOf():根据给定的字符串,返回他的位置public String[] split(String regex)-----------
该方法用于分割字符串
字符串截取substring
- public static void main(String[] args) {
- String s = "helloworld";
- String s1 = s.substring(2); 截取从指定位置到字符串结束的子字符串
- String s2 = s.substring(2, 7); 截取从指定位置开始,到endIndex-1位置的子字符串
- String s3 = (String) s.subSequence(2, 7); 和substrin一样
- System.out.print("s1:"+s1+"\n"+"s2:"+s2+"\n"+"s3:"+s3);
- }
输出:
s1:lloworld
s2:llowo
s3:llowo
- package com.xtfggef.string;
- public class StringSpilt {
- public static void main(String[] args) {
- String s = "helloworld";
- String[] s2 = s.split("abc");
- for (int i = 0; i < s2.length; i++) {
- System.out.println(s2[i] + " " + i);
- }
- }
- }
package com.xtfggef.string;
public class StringSpilt {
public static void main(String[] args) {
String s = "helloworld";
String[] s2 = s.split("abc");
for (int i = 0; i < s2.length; i++) {
System.out.println(s2[i] + " " + i);
}
}
}
输出:helloworld 0
s1+"b"和"a"+"b"的不同
- String s = "ab";
- String s1 = "a";
- String s2 = s1 + "b";
- String s3 = "ab";
- System.out.println(s == s2);//false
- System.out.println(s2 == s3);//false
- System.out.println(s2.hashCode() == s3.hashCode());
- String s4 = "ad";
- String s5 = "a" + "d";
- String s6 = "ad";
- System.out.println(s4 == s5);//true
- System.out.println(s4 == s6);//true
- System.out.println(s1.hashCode()); 97
- System.out.println(s2.hashCode()); 3105
- System.out.println(s3.hashCode()); 3105
- System.out.println(s4.hashCode()); 3107
- System.out.println(s5.hashCode()); 3107
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println(s5.hashCode());
为什么s1+"b"会产生新的对象?而没有去常量池查找是否已经存在ab对象,以致于s==s2返回false。因为我们说过常量池(下文会讲常量池)是在编译期确定好的,所以如果我们的语句时String s5 = "ab"的话,这个是在编译期确定的,会去常量池查找,而此处我们的语句时s2 = s1+"b",s2的值只有在运行期才能确定,所以不会去常量池查找,也就是产生新串
s2在堆上分配,因为+的内部实现是用StringBuilder来实现的。String s2 = s1+"b" 内部是这样实现的:String s2 = new StringBuilder(s1).append("b").toString();所以是在堆上来分配的
s2.hashCode() == s3.hashCode()返回trueStringBuffer、StringBuilder
1、初始化
StringBuffer和StringBuilder就是所谓的可变字符串类,共四个构造方法:
StringBuffer()
public StringBuffer(int paramInt)
public StringBuffer(String paramString)
public StringBuffer(CharSequence paramCharSequence)
观察其源码发现,使用StringBuffer()时,默认开辟16个字符的长度的空间,使用public StringBuffer(int paramInt)时开辟指定大小的空间,使用public StringBuffer(String paramString)时,开辟paramString.length+16大小的空间。都是调用父类的构造器super()来开辟内存。这方面StringBuffer和StringBuilder都一样,且都实现AbstractStringBuilder类
2.区别
二者几乎没什么区别,基本都是在调用父类的各个方法,一个重要的区别就是StringBuffer是线程安全的,内部的大多数方法前面都有关键字synchronized,这样就会有一定的性能消耗,StringBuilder是非线程安全的,所以效率要高些。
- public static void main(String[] args) throws Exception {
- String string = "0";
- int n = 10000;
- long begin = System.currentTimeMillis();
- for (int i = 1; i < n; i++) {
- string += i;
- }
- long end = System.currentTimeMillis();
-----------------------public synchronized int length()--------------------------
-------------------------public synchronized int capacity()---------------------------
二者都是获取字符串的长度,length()获取的是当前字符串的长度,capacity()获取的是当前缓冲区的大小。举个简单的例子:
- StringBuffer sb = new StringBuffer();
- System.out.println(sb.length());;
- System.out.println(sb.capacity());
StringBuffer sb = new StringBuffer();
System.out.println(sb.length());;
System.out.println(sb.capacity());
输出:
0
16
- StringBuffer sb = new StringBuffer("hello");
- System.out.println(sb.length());;
- System.out.println(sb.capacity());
StringBuffer sb = new StringBuffer("hello");
System.out.println(sb.length());;
System.out.println(sb.capacity());
输出:
5
21
因为默认分配16个字符大小的空间,所以不难解释上面的结果。
- long between = end - begin;
- System.out.println("使用String类耗时:" + between+"ms");
- int n1 = 10000;
- StringBuffer sb = new StringBuffer("0");
- long begin1 = System.currentTimeMillis();
- for (int j = 1; j < n1; j++) {
- sb.append(j);
- }
- long end1 = System.currentTimeMillis();
- long between1 = end1 - begin1;
- System.out.println("使用StringBuffer类耗时:" + between1+"ms");
- int n2 = 10000;
- StringBuilder sb2 = new StringBuilder("0");
- long begin2 = System.currentTimeMillis();
- for (int k = 1; k < n2; k++) {
- sb2.append(k);
- }
- long end2 = System.currentTimeMillis();
- long between2 = end2 - begin2;
- System.out.println("使用StringBuilder类耗时:" + between2+"ms");
- }
public static void main(String[] args) throws Exception {
String string = "0";
int n = 10000;
long begin = System.currentTimeMillis();
for (int i = 1; i < n; i++) {
string += i;
}
long end = System.currentTimeMillis();
long between = end - begin;
System.out.println("使用String类耗时:" + between+"ms");
int n1 = 10000;
StringBuffer sb = new StringBuffer("0");
long begin1 = System.currentTimeMillis();
for (int j = 1; j < n1; j++) {
sb.append(j);
}
long end1 = System.currentTimeMillis();
long between1 = end1 - begin1;
System.out.println("使用StringBuffer类耗时:" + between1+"ms");
int n2 = 10000;
StringBuilder sb2 = new StringBuilder("0");
long begin2 = System.currentTimeMillis();
for (int k = 1; k < n2; k++) {
sb2.append(k);
}
long end2 = System.currentTimeMillis();
long between2 = end2 - begin2;
System.out.println("使用StringBuilder类耗时:" + between2+"ms");
}
输出:
使用String类耗时:982ms使用StringBuffer类耗时:2ms
使用StringBuilder类耗时:1ms
虽然这个数字每次执行都不一样,而且每个机子的情况也不一样,但是有几点是确定的,String类消耗的明显比另外两个多得多。还有一点就是,StringBuffer要比StringBuilder消耗的多,尽管相差不明显
------------------public boolean equals(Object paramObject)---------------------
- StringBuffer sb = new StringBuffer("hello");
- StringBuffer sb2 = new StringBuffer("hello");
- System.out.println(sb.equals(sb2)); //false
另外StringBuffer有一系列追加、插入、删除字符串的方法,首先append(),就是在原来的字符串后面直接追加一个新的串,和String类相比有明显的好处:
String类在追加的时候,源字符串不变(这就是为什么说String是不可变的字符串类型),和新串连接后,重新开辟一个内存。这样就会造成每次连接一个新串后,都会让之前的串报废,因此也造成了不可避免的内存泄露。
- StringBuffer sb = new StringBuffer("helloworld, ");
- sb.append("I'm ").append("erqing ").append("who ").append("are you ?");
- System.out.println(sb);
- //public synchronized StringBuffer insert(int paramInt, Object paramObject)
- sb.insert(12, /*9*/"nice! ");
- System.out.println(sb);
- //public synchronized StringBuffer reverse()
- sb.reverse();
- System.out.println(sb);
- sb.reverse();
- System.out.println(sb);
- //public synchronized StringBuffer delete(int paramInt1, int paramInt2)
- //public synchronized StringBuffer deleteCharAt(int paramInt)
- sb.delete(12, 18);
- System.out.println(sb);
- sb.deleteCharAt(5);
- System.out.println(sb);
//append()
StringBuffer sb = new StringBuffer("helloworld, ");
sb.append("I'm ").append("erqing ").append("who ").append("are you ?");
System.out.println(sb);
//public synchronized StringBuffer insert(int paramInt, Object paramObject)
sb.insert(12, /*9*/"nice! ");
System.out.println(sb);
//public synchronized StringBuffer reverse()
sb.reverse();
System.out.println(sb);
sb.reverse();
System.out.println(sb);
//public synchronized StringBuffer delete(int paramInt1, int paramInt2)
//public synchronized StringBuffer deleteCharAt(int paramInt)
sb.delete(12, 18);
System.out.println(sb);
sb.deleteCharAt(5);
System.out.println(sb);
输出:
helloworld, I'm erqing who are you ?
helloworld, nice! I'm erqing who are you ?
? uoy era ohw gniqre m'I !ecin ,dlrowolleh
helloworld, nice! I'm erqing who are you ?
helloworld, I'm erqing who are you ?
helloorld, I'm erqing who are you ?
-----------------public synchronized void trimToSize()---------------------
该方法用于将多余的缓冲区空间释放出来。
- StringBuffer sb = new StringBuffer("hello erqing");
- System.out.println("length:"+sb.length());
- System.out.println("capacity:"+sb.capacity());
- sb.trimToSize();
- System.out.println("trimTosize:"+sb.capacity());
StringBuffer sb = new StringBuffer("hello erqing");
System.out.println("length:"+sb.length());
System.out.println("capacity:"+sb.capacity());
sb.trimToSize();
System.out.println("trimTosize:"+sb.capacity());
输出:
length:12
capacity:28
trimTosize:12
StringBuffer类还有很多方法,关于字符查找,截取,替换方面的方法,有兴趣的童鞋可以去研究研究源码,定会学到不少知识!