在Java中,字符串是对象,是描述字符的基本数据结构,也是程序设计中很重要的一类数据结构
Java专门为存储和处理字符串提供了两个类: String & StringBuffer
String类型对象的创建常见的有三种方法 :
1. 通过初始化 String str = "hellow";
2. 使用new关键字进行创建 String str = new String();
3. 通过类型转换来创建 String str = Double.toString(123.45);
String类常用方法的总结:
1.String求长度的方法 : public int length();
1 String s1 = Double.toString(1234.5678); 2 System.out.println("the length of s1 "+ s1 + " is :" +s1.length());
2.截取方法: public String substring(int begin); 返回从begin开始到最后的字符串
public String substring(int begin, int end);
1 String sub1 = s1.substring(5); 2 String sub2 = s1.substring(2, 7); 3 System.out.println(sub1); 4 System.out.println(sub2);
3.转字符串数组方法 : public String[] split(String regex);
1 /** 2 *常用的通过空格来分割字符串的方法 3 */ 4 String s2 = "my name is gap, i study in USTC!"; 5 String snum[] = s2.split(" {1,}"); 6 for(int i=0; i<snum.length; i++) { 7 System.out.println(snum[i]); 8 }
4.确定子字符串位置的方法:public int indexOf(String str);
public int indexOf(String str, int fromIndex);
1 int n1 = s2.indexOf("ga"); 2 System.out.println(s2.indexOf('i')); //输出为8即is中的i 3 System.out.println(s2.indexOf('i', 12)); //输出为16即,i中的i
然后附上一道很有趣的面试题,同时也能够加深对java内存分配的理解:
1 public class Test { 2 public static void main(String[] args) { 3 //下列4行程序各创建了几个对象 4 String str1 = new String("hello"); 5 String str2 = "hello"; 6 7 String str3 = new String("hello"); 8 String str4 = "hello"; 9 10 System.out.println(str1.equals(str3)); 11 System.out.println(str1 == str2); 12 System.out.println(str1 == str3); 13 System.out.println(str2 == str3); 14 System.out.println(str2 == str4); 15 } 16 }
第4~8行语句在执行的时候分别创建了几个对象?10~14语句输出结果为什么?
第四行语句执行的时候会创建两个对象,第四条语句执行的顺序依次为 1.在栈上为str1分配空间 2.在String pool(String池)即内存data segment中创建对象“hello” 3.在堆中创建“hello”对象 4. 把引用赋给str
第五行语句执行的时候不会创建对象,因为首先会检查String池中是否有"hello"这个对象,有则str2直接指向String池中的“hello”;
第七行语句执行的时候会创建一个对象,即堆上创建"hello"对象;
同理,第八行语句执行的时候也不会创建对象,值得注意的是由于String池中只有一个"hello"对象,因此str2与str4实际上指向同一块内存区域,因此str2 == str4 ;
运行结果如图所示:
总结一下,当JVM在运行用双引号引起来的一个字符串的代码时,即当Java虚拟机(JVM)遇到双引号操作符,它会先到String的对象池中去检查是否有一个字符串序列相同的对象,如果有,就取现成的对象;如果没有,则在对象池中创建,并且返回其引用。当然,如果有new关键字的话,除了上述步骤还会在堆中创建一个新的String对象。对象池的存在是为了避免频繁的创建和销毁对象而影响系统的性能。
看完String,再来看看StringBuffer,先看一段程序:
1 public class TestStringBuffer { 2 public static void main(String[] args) { 3 String a = "a"; 4 String b = "b"; 5 String c = "c"; 6 String d = "d"; 7 String abcd = a + b + c + d; 8 } 9 10 }
试想在以上的代码中,总共创建了几个对象?答案是 7 个。 首先对于变量a,b,c,d,它们都是通过双引号的形式创建的String对象。
而abcd变量则是通过4者通过+相连得到的,在相连的过程中,首先执行的是a+b操作,产生了ab字符串,然后加上c,产生了abc字符串,最后加上d得到abcd的String对象。
通过上例可以看出,通过String直接相加来拼接字符串的效率是极低,其中可能会产生大量冗余的字符串,例如ab,abc。
试想如果程序中有成千上万的字符串需要拼接,如果使用String的话此时JVM的负荷是很大的,会严重的影响到程序的性能。所以如果遇到大量字符串拼接操作的话,应该使用StringBuffer和StringBuilder类。
StringBuffer和StringBuilder类的功能和API类似,StringBuilder是线程安全的。
然后手贱把上面的程序改了下:
1 public class TestStringBuffer { 2 public static void main(String[] args) { 3 String a = "a"; 4 String b = "b"; 5 String c = "c"; 6 String d = "d"; 7 String abcd = a + b + c + d; 8 System.out.println(abcd == "abcd"); 9 10 11 String s1 = new String("a"); 12 s1 = s1 + "b"; 13 System.out.println(s1 == "ab"); 14 15 String s2 = "a" + "b"; 16 System.out.println(s2 == "ab"); 17 } 18 19 }
结果如图:
然后上网查了下,也还没弄清楚其中的道理,先挖个坑,之后懂了再来把坑填上~~