Java基础笔记(十一)—— 字符串与数组
字符串的声明与初始化主要两种:String s1=new String("abc"); 或 String s2="abc";
String s1="abc"; //(1)在常量区里存放了一个"abc"字符串对象 String s2="abc"; //(2)s2引用常量区中的对象,不会创建新对象 String s3=new String("abc"); //(3)在堆中创建新对象 String s4=new String("abc"); //(4)在堆中又创建新对象
1.
JVM中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用。创建字符串常量 String s="abc";,会首先在字符串常量池中查找是否已经有相同的字符串被定义(由String类equals(Object obj)方法的返回值来判断)。若已经定义,则直接获取对其的引用,此时不需要创建新的对象;若没有定义,则首先创建这个字符串对象,然后把它加入到字符串池中,再将它的引用返回。
2.
new String("abc")会调用String类的构造函数public String(String original){},传入一个字符串常量,所以此语句相当于“abc”和new String()两个操作。若字符串常量池中不存在“abc”,则会创建一个字符串常量"abc",并将其添加到字符串池中;若存在,则不创建,然后new String()会在堆中创建一个新的对象(只要用到new总会生成新的对象),所以s3与s4指向的是堆中不同的String对象,地址也就不同。即两个内容相同的字符串对象"abc",它们在内存中的地址是不同的。
例:new String("abc")创建几个对象?
答:一个或两个。如果常量池中原来有"abc",那么只创建一个对象;如果常量池中没有字符串"abc",那么就会创建两个对象(一个常量区的"abc"字符串对象,一个在堆中new的String对象)。
3.
由于String是不可变类,一旦创建好了就不能被修改,因此String对象可以被共享而且不会导致程序的混乱。(不可变,就是其值不可变,如果想要拥有新值,只能再创建,开辟一块新的内存空间来存储。)
4.
String s;
s=null; //s是一个字符串类型的引用,它不指向任何一个字符串。
s=" "; //s是一个字符串类型的引用,它指向另外一个字符串,这个字符串的值为" ",即空字符串。
5.
"=="运算符用来比较两个变量对应的内存中存储的数值是否相同。
String s=new String(); 变量s占用一块存储空间,而new String()则存储在另一块存储空间里,此时,变量s对应内存中存储的数值是对象占用的那块内存的首地址。如果比较两个变量是否指向同一个对象,可以用"=="比较(看存储的地址值是否相同),但如果要比较两个对象的内容是否相等,那么"=="无法实现。(比如上图中的s3和s4,如果比较它俩是否指向同一个对象,可以用"==",但是要比较它俩分别对应的堆中的两个对象的内容值是否相同,就要用equals方法。)
equals是Object类提供的方法之一,每一个Java类都继承自Object类,所以每一个对象都具有equals方法。String类的equals方法是用于比较两个独立对象的内容是否相同,即堆中的内容是否相同。
例:String s1=new String("Hello");
String s2=new String("Hello");
两条new语句创建了两个对象,然后用s1、s2两个变量分别指向一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,但两个对象中的内容是相同的。
所以,s1==s2会返回false,s1.equals(s2)会返回true。
如果s2=s1,s1==s2会返回true。
6.
Java中有5个类可以对字符或字符串进行操作:Character、String、StringBuffer、StringBuilder、StringTokenizer。
Character
用于单个字符操作。
String
用于字符串操作,属于不可变类,所以适合在需要被共享的场合中使用,如果用String保存一个经常被修改的字符串,会生成很多无用的对象,被垃圾回收器回收,影响程序性能,执行效率低。初始化方式:构造函数方式和赋值方式均可:String s=new String("world"); 或 String s="hello";
StringBuffer
字符串缓冲区,用于字符串操作,属于可变类,所以适合保存经常被修改的字符串,会比String少很多附加操作。初始化方式:只能使用构造函数方式:StringBuffer s=new StringBuffer("hello");
字符串修改的两种方式:
1.
String s="hello";
s+="world";
2.
StringBuffer s=new StringBuffer("hello");
String s1="world";
s.append(s1);
如果字符串修改次数多,StringBuffer要比String(第2种比第1种)运行效率高很多。
StringBuilder
字符串缓冲区,但不是线程安全的,如果只是在单线程中使用字符串缓冲区,那么StringBuilder的效率会更高些。所以,在只有单线程访问时可以使用StringBuilder,当有多个线程访问时,最好使用线程安全的StringBuffer。因为StringBuffer必要时可以对这些方法进行同步,所以任意特定实例上的所有操作好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
在执行效率上,从高到低,依次是StringBuilder、StringBuffer、String。一般地,如果要操作的数据量比较小,优先使用String类;如果在单线程下操作大量数据,优先使用StringBuilder类;如果在多线程下操作大量数据,优先使用StringBuffer类。
StringTokenizer
分割字符串的工具类
import java.util.StringTokenizer; public class Test { public static void main(String[] args){ StringTokenizer s=new StringTokenizer("Hello my friends"); while (s.hasMoreTokens()) { System.out.println(s.nextToken()); } } } //运行结果: Hello my friends