Java之String类与StringBuffer类

Java之String类与StringBuffer类

一、String类

1.实例化方式

1)直接赋值法

String str="abc";

String类的设计采用了共享设计模式。在JVM底层实际上会自动维护一个对象池(字符串对象池),如果采用直接赋值法赋值,JVM会先在对象池中查找,如果有,则直接引用;如果没有,则将该实例化对象放到对象池中。

所谓对象池就是一个对象数组。优点:减少内存的开销。

2)构造法

String str=new String("abc");

Java之String类与StringBuffer类

由此可知,如果使用构造法就会开辟两块内存空间,并且其中一块会变为垃圾空间。而且,当new两个相同字符串时,并不会像直接赋值法那样,而是会再次创建开辟内存空间,因此,它的缺点是:容易制造垃圾,不能实现字符串共享。

先开辟的那个对象为匿名对象,new开辟空间后,匿名对象空间就变为了垃圾空间。

2.字符串的相等比较

"=="在基本数据类型中比较的是数值的大小,但是在引用数据类型中,用于对象比较,比较的是两个对象所保存的内存地址数值,而没有比较对象的内容。

public class TestString {
    public static void main(String[] args) {
        int a=1;
        int b=1;
        System.out.println(a==b);//true

        String str1="abc";//直接赋值法
        String str2=new String("abc");//构造法
        System.out.println(str1==str2);//false
    }
}

要想比较字符串的内容,必须采用String类提供的equals方法。

  public boolean equals(Object anObject)
public class TestString {
    public static void main(String[] args) {
        String str1="abc";//直接赋值法
        String str2=new String("abc");//构造法
        System.out.println(str1==str2);//false
        System.out.println(str1.equals(str2));//true
    }
}

String类中“==”与"equals"的区别?

“==”用于比较对象的堆空间地址的大小;而equals方法用于比较两个字符串的内容是否相等。

3.String的匿名对象

在任何语言的底层,都不会提供有直接的字符串类型。现在所谓的字符串只是高级语言提供给用户开发的支持而已。在Java中,也没有直接提供字符串常量的概念。所有使用“”定义的被人本质上都是String的匿名对象。

Java之String类与StringBuffer类

匿名对象保存在堆内存中。

建议:在以后的开发过程中,如果要判断用户输入的字符串是否等同于特定字符串,一定要先将特定字符串写在前面。

如:

import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String input=sc.next();
        System.out.println(input.equals("hello"));//可能会抛出空指针异常,NUllPointerException异常
        System.out.println("hello".equals(input));
    }
}

如果用户输入为空,就会抛出异常,为避免此异常,我们通常将特定字符串写在前面。推荐第二种写法。

任何的字符串都是String的匿名对象,所以该对象不会为null。

4.构造法的String对象入池

在String类中,提供有intern()使String对象入池。

import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        String s1=new String("abc");
        String s2="abc";
        System.out.println(s1.equals(s2));//true
        System.out.println(s1==s2);//false
        String s3=s1.intern();
        System.out.println(s3==s2);//true
        System.out.println(s1.intern()==s2);//true
    }
}

5.字符串常量不可变更

所有语言对字符串的底层实现,都是字符数组。而数组最大的缺陷就是长度固定,因此在定义字符串常量时,它的内容不可改变。

      String str="hello";
      str=str+"world";
      str+="!!!";
      System.out.println(str);

以上字符串的变更属于字符串对象的变更,而非字符串常量的变更,改变的是字符串对象的引用。这个过程*产生了5个对象,而且都不在对象池中,而是在堆空间中。

String str="hello"+" world"+"!!!";//编译器会将它优化为String str="hello world!!!"

开发原则:

1)字符串定义采用直接赋值法。

2)字符串内容的比较采用String类的equals方法。

3)字符串不应该改变太多,避免产生大量垃圾。

6.与字符串有关的一些方法

6.1 与字符相关的一些方法

public String(char[] value);//将字符数组中的所有内容变为字符串
public String(char[] value,int offset,int count);//将部分字符数组中的内容变为字符串,从下标为offset处开始,取长度为count的字符。
public char charAt(int index);//取得指定索引处得字符,索引从0开始。
public char[] toCharArray();//将字符串变为普通数组返回
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        char[] ch=new char[]{'J','a','v','a',' ','S','E'};
        String str=new String(ch);
        String str2=new String(ch,1,5);
        System.out.println(str);//Java SE
        System.out.println(str2);//ava S
        char c=str.charAt(5);
        System.out.println(c);//S
        String str3="hello";
        char[] chars=str3.toCharArray();
        for(int i=0;i<chars.length;i++){
            System.out.print(chars[i]+" ");//h e l l o
        }
        System.out.println();
    }
}

6.2 与字节有关的方法

字节常用于数据传输以及编码转换的处理中,在String类中提供有字节的支持。

字节并不适合处理中文,只有字符适合处理中文。一个字符等于两个字节。字节只适合处理二进制数据。

public String(byte[] bytes);//将字节数组变为字符串
public String(byte[] bytes,int offset,int length);//将部分字节数组中的内容变为字符串
public byte[] getBytes();//将字符串以字节数组的形式返回
public byte[] getBytes(String charsetName);//编码转换处理
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        String str="helloworld";
        byte[] data=str.getBytes();
        for(int i=0;i<data.length;i++){
            data[i]-=32;
            System.out.print(data[i]+" ");
        }
        System.out.println();
        System.out.println(new String(data));
    }
}

Java之String类与StringBuffer类

6.3 字符串比较

public boolean equals(Object anObject);//区分大小写的比较
public boolean equalsIgnoreCase(String anotherString);//不区分大小写的比较
public int compareTo(String anotherString);//比较两个字符串的大小关系 相等,返回0;小于,返回内容小于0;大于,返回内容大于0.
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        String str1="hello";
        String str2="HELLO";
        System.out.println(str1.equals(str2));
        System.out.println(str1.equalsIgnoreCase(str2));
        System.out.println(str1.compareTo(str2));
    }
}

Java之String类与StringBuffer类

6.4 字符串查找

public boolean contains(CharSequence s);//判断一个子字符串是否存在
public int indexOf(String str);//从头开始查找指定字符串的位置,查到了返回位置的开始索引,没有找到返回-1.
public int indexOf(String str,int fromIndex);//从指定位置开始查找子字符串位置,查不到返回-1.
public int lastIndexOf(String str);//由后向前查找子字符串位置
public int lastIndexOf(String str,int fromIndex);//从指定位置由后向前开始查找子字符串位置。
public boolean startsWith(String prefix);//判断是否以指定字符串开头
public boolean startsWith(String prefix,int toffset);//从指定位置开始判断是否以指定字符串开头
public boolean endsWith(String suffix);//判断是否以指定字符串结尾

查找字符串,最好用最方便的是contains(String str)方法。该方法是在JDK1.5以后才有的。

使用indexOf,如果内容重复,则只返回查找的第一个位置。

6.5 字符串替换

public String replaceAll(String regex,String replacement);//替换所有的指定内容
public String replaceFirst(String regex,String replacement);//替换首个指定内容

6.6 字符串拆分

public String[] split(String regex);//将字符串拆分
public String[] split(String regex,int limit);//将字符串部分拆分,该数组长度就是limit极限。
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
       String str="Java SE is best";
       String[] strings=str.split(" ");
       for(String s:strings){
           System.out.println(s);
       }
        System.out.println("================================");
       String[] res=str.split(" ",2);
       for(String s:res){
           System.out.println(s);
       }
    }
}

Java之String类与StringBuffer类

6.7 字符串截取

public String substring(int beginIndex);//从指定索引截取到结尾
public String substring(int beginIndex,int endIndex);//截取部分内容,不包括endIndex处的字符
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
       String str="Java SE is best";
       String str1=str.substring(11);
        System.out.println(str1);
        String str2=str.substring(0,7);
        System.out.println(str2);
    }
}

Java之String类与StringBuffer类

注意:substring(int beginIndex,int endIndex);截取的字符串不包括endIndex处的字符。

6.8 字符串其它操作方法 

public String trim();//去掉字符串中的左右空格,保留中间空格。
public String toUpperCase();//字符串转大写
public String toLowerCase();//字符串转小写
public native String intern();//构造法的字符串入池操作
public String concat(String str);//字符串连接,等同于"+",不入池。
public int length();//取得字符串长度
public boolean isEmpty();//判断是否为空字符串,但不是null,而是长度为0.
import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
       String str="  Java SE is best   ";
        System.out.println(str);
        System.out.println(str.trim());
        System.out.println(str.toUpperCase());
        System.out.println(str.toLowerCase());
        System.out.println(str.concat("yes"));
        System.out.println(str.length());
    }
}

Java之String类与StringBuffer类

二、StringBuffer类

字符串常量不能修改,为了方便字符串的修改,提供StringBuffer类。在String类中使用"+"进行字符串连接,但是在StringBuffer类中使用append(str)函数来实现。

1.StringBuffer类的构造方法

a.StringBuffer()//建立一个空的字符缓冲区,初始容量为16个字符。
b.StringBuffer(int length)//指定字符长度为length,建立空的字符缓冲区。
c.StringBuffer(String str)//缓冲区的初始内容为str,并另外提供16个字符的初始容量。

说明:即使两个StringBuffer类的对象,内容相同,但是用equals()函数,比较其内容,结果仍然为false.

2.String类和StringBuffer类的相互转换

String类型转为StringBuffer类:StringBuffer的构造方法或者append()。

StringBuffer类型转为String类型:调用toStirng()。

import java.util.Scanner;

public class TestString {
    public static void main(String[] args) {
        StringBuffer s1=new StringBuffer();
        s1.append("hello world");
        StringBuffer s2=new StringBuffer();
        System.out.println(s2.append("hello world").toString());
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1==s2);//false
        System.out.println(s1.equals(s2));//false
        String str="hello";
        System.out.println(str.toString());
    }
}

Java之String类与StringBuffer类

3.StringBuffer的常用方法

3.1 与String类用法相同的方法

 (1)length()//返回字符串的字符个数。
 (2)toString()//返回缓冲区中的字符串。(两个类函数的实现方法不同,具体见2.3.2)
 (3)charAt(int index)//返回字符串中下标是index的字符。
 (4)getChars(int srcBegin,int secEnd,char[] dst,int dstBegin)//将字符串下标为[srcBegin,srcEnd)的字符串赋值给dst从下标为
                                dstBegin开始的一组字符。
 (5)substring(int beginIndex,int endIndex)//返回原字符串的一个子串[beginIndex,endIndex)

3.2 StringBuffer类独有的方法

1)setCharAt(int index,char ch)//在下标为index的位置上添加字符ch,相当替换该位置上的原有字符。

public class Astring{
	public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("world");
		System.out.println(s1.charAt(3));//l
		s1.setCharAt(3,'h');
		System.out.println(s1);//worhd
	}
}

2)append()//向缓冲区中添加新的字符串。

public class Astring{
	public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("hello");
		System.out.println(s1);//hello
		s1.append(" world");
		System.out.println(s1);//hello world
	}
}

3)insert(int Offset,String str);//在字符串中的offset位置插入字符串str.(不替换)

public class Astring{
	public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("hello");
		System.out.println(s1);//hello
		s1.append(" world");
		System.out.println(s1);//hello world
		s1.insert(5,"!!!");
		System.out.println(s1);//hello!!! world
	}
}

4)reverse()//字符串反转函数。

public class Astring{
	public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("hello");
		System.out.println(s1);//hello
		System.out.println(s1.reverse());//olleh
	}
}

5)delete(int start,int end)//删除指定范围的数据 [start,end)

public class Astring{
	public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("hello");
		System.out.println(s1);//hello
		System.out.println(s1.delete(1,4));//ho
	}
}

4.比较String类与StringBuffer类

相同点:

    (1)String类与StringBuffer类都用来处理字符串。
    (2)部分方法在二者中的用法是相同的。eg:length()、toString()、charAt()、substring().
    (3)在这两个类中,字符的索引都是从0开始的。
    (4)这两个类都是CharSequence的子类。CharSequence接口描述的是一系列字符集。

不同点:

(1)String类是不可变类,因为在底端是用字符数组实现的,而数组长度固定,一旦赋值,就不能在原来的字符串上进行修改可能会浪费空间。StringBuffer类是可变类,能够在原来的数组上进行修改。

如:String类中的substring()、concat()、toLowerCase()、toUpperCase()和trim()等方法都不会改变字符串本身,
而是直接创建并返回一个包含改变后内容的新字符串对象。而StringBuffer的apend()、replaceAll()、insert()、setCharAt()等
方法都会改变字符串缓冲区中的字符串内容。

(2)String类覆盖了Object类的equals()方法,而StringBuffer类没有覆盖该方法。

(3)虽然两个类都覆盖了toString()方法,但各自的实现方式不同。String类的toString()方法返回当前String对象的引用。而StringBuffer类的toString()方法返回一个以当前StringBuffer的缓冲区的所有字符为内容的新的String对象的引用。

(4)String类对象可以用操作符"+"进行连接,而StringBuffer类的对象不能,StringBuffer类的对象可以通过append()方法添加新的字符串。

public class Astring{
	     public static void main(String[] args){
		StringBuffer s1=new StringBuffer();
		s1.append("fjasgnroehoergklfjij");
		StringBuffer s2=new StringBuffer();
		System.out.println(s2.append("fjasgnroehoergklfjij").toString());
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s1==s2);//false
		System.out.println(s1.equals(s2));//false
		String str="hello";
		System.out.println(str.toString());
	}
}

5.比较String、StringBuffer与StringBuilder

   (1)String的内容不可修改,而StringBuffer和StringBuilder的内容可以修改。
 (2)StringBuffer采用同步处理,属于线程安全操作,而StringBuilder采用异步处理,属于线程不安全操作。