字符串的声明
字符串是内存中连续排列的0个或多个字符。不变字符串是指字符串一旦创建,其内容就不能改变,Java中使用String类来处理不变字符串,在对String类的实例进行查找、比较、拼接等操作时,既不能输入新字符,又不能改变字符串的长度。
Java程序中的字符串分为常量和变量两种,其中,字符串常量使用双引号括起来的一串字符,系统为程序中出现的字符串常量自动创建一个String对象。例如:
System.out.println("hello world!");
这句话将创建一个String对象,值为“hello world!”。
对于字符串变量,在使用之前要显式声明,并进行初始化。
字符串的声明方式有三种:
- 直接创建:
字符串是对象,虽然我们在这里没有用new创建对象,其实是编译器给我们做了这些操作。这种创建的字符串对象有一个特点,如果同样的对象如果存在了,就不会创建一个新的对象,而是指向了同样的对象。例如String str2 = "Hello";,则str1和str2是指向了字符串池中同样的内存地址,即 str1 == str2。
- 使用字符串连接创建: String str = "Hello" + "World";
这种形式其实可以看做是第一种的形式的特殊形式。 "Hello" + "World"在编译期会被自动折叠为常量“HelloWorld”,所以,最后只会创建一个对象:String str = "HelloWorld";
JDK1.7开始,javac会进行常量折叠,全字面量字符串相加是可以折叠为一个字面常量,而且是进入常量池的。这个问题涉及到了字符串常量池和字符串拼接。
String a="a"+"b"+"c";
通过编译器优化后,得到的效果是:
String a="abc";
- new创建字符串:
用new关键字创建的字符串每次都会创建一个新的对象。即使这时创建一个字符串
String str2 = new String("Hello");
str1与str2是两个对象,str1 != str2。
注意点:String str = new String("Hello"); 会产生几个对象?
如果字符串池里面没有“Hello”对象,会在字符串池里面生成一个对象,然后再生成一个字符串对象,str指向这个对象;如果字符串池里面已经有了“Hello”对象,则只会生成一个对象,str指向这个对象。
字符串的操作
字符串创建以后,可以使用字符串类中的方法对它进行操作。日常开发中常用的操作字符串的方法有:
- String当中与获取相关的常用方法
public int length():获取字符串当中含有的字符个数,拿到字符串长度。
public String concat(String str):将当前字符串和参数字符串**拼接**成为返回值新的字符串。
public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始。)
public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。
- 字符串的截取方法
public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。
public String substring(int begin, int end):截取从begin开始,一直到end结束,中间的字符串。
备注:[begin,end),包含左边,不包含右边。
- 字符串转换的方法
public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
public byte[] getBytes():获得当前字符串底层的字节数组。
public String replace(CharSequence oldString, CharSequence newString):
将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
备注:CharSequence意思就是说可以接受字符串类型。
- 分割字符串
public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。
注意事项:
split方法的参数其实是一个“正则表达式”。
转义必须写"."(两个反斜杠)
如果split失败则返回一个空字符串数组,比如split(".")就会失败,正则不明确,程序不知道怎么切了。
字符串的比较
String字符串可以使用“==”和equals()方法比较。当两个字符串使用“==”进行比较时,比较的是两个字符串在内存中的地址。当两个字符串使用equals方法比较时,比较的是两个字符串的值是否相等。
上面例子中,s1 和 s2 使用相同的字符串常量来定义,相同的字符串常量在系统内部只存在一个,即 s1 和 s2 都指向这同一个常量,所以使用 “==” 或 “equals”方法来判断时,结果都是相等的。而 s3 是使用字符串常量创建的另一个对象,虽然它与 s1 所含的字符是一样的,但却是不同的对象,故使用 “==” 判断时,s1 和 s3 是不相等的。类似的,s4 也是另一个对象,使用 “==” 判断时,s3 和 s4 页是不相等的。而 s5 与 s1 指向同一个实例,所以他们在两种方式下的比较都是相等的。
String、StringBuffer和StringBuilder的关系
String类的对象实例是不可变的,一旦创建就确定下来,对字符串施加操作后并不改变字符串本身,而是有生成了一个实例。对于那些需要改变内容并有许多操作的字符串,可以使用StringBuffer类或者StringBuilder类。它们之间的区别如下:
- String是字符串常量,一旦创建就不能修改。对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。String类是final修饰的,不能被继承。覆盖了equals方法和hashCode()方法。
- StringBuffer是字符串可变对象,可以对字符串进行操作,修改字符串原有值时不会新建一个对象。执行效率较慢,但是线程安全。StringBuffer没有覆盖equals方法和hashCode()方法。可以动态的拼接字符换,使用 append() 方法。
- StringBuilder也是字符串可变对象,同StringBuffer一样,可以对字符串进行操作,也不会新建对象。执行效率高效,但是线程不安全。