String,StringBuffer,StringBuilder

197 阅读6分钟

1.String

1.1 String介绍

Java为了处理字符序列引入String类,java把String类定义为final类,因此String类不可以有子类,用户不能拓展String类。

1.2 关于String对象

String常量

String常量是用双引号括起的字符序列,如:

"asasa"

"你好"

常量放在常量池中,由于常量也是对象,常量池中放着引用~~~~和实体,注意的是常量池在程序运行期间不允许改变。

对于常量向String对象的赋值,是把常量的引用赋值给String对象,如果给两个对象赋值相同的常量,如:

String s1="qwer";

String s2="qwer";

s1和s2里放着相同的引用,即"qwer"的引用

动态区 常量池

此时若是对s2进行新的赋值,不会改变常量池的内容(程序运行期间不变),而是改变动态区s2所存引用,如:

s2="qqqqq";

String对象

String类可以使用new来声明对象并创建对象。

String s1 =new String("ssssss");

String s2 =new String("ssssss");

s1和s2虽然赋值相同,但他们内部存储的引用不同。因为其用new运算符分配空间后存入字符序列,得到引用后赋值给s1和s2(new运算出的对象都不在常量池中)。

以下仅为目前的认知

对于String类来说,不管是使用常量赋值给String对象,还是用new运算符开辟空间,如:

String s1="qwe";

String s2=new String("qwer");

他们都会在常量池生成对应的字符串,只是s1是直接把在常量池的字符串对应的引用直接给s1,而s2是先在常量池中检查是否有“qwer”,如果没有,就在常量池中创建。然后再把其拷贝到堆中,把堆中的引用给s2。

如果用new创建多个相同的,如:

String s2=new String("qwer");

String s3=new String("qwer");

则在堆中拷贝对应的份数的字符串,然后把引用分别给对应的对象,因此比较时有如下情况:

String s1="qwe";

String s2="qwe";

s1==s2//true

String s3=new String("qwer");

String s4=new String("qwer");

s3==s4//false

1.3常用的构造方法

  1. String (char a[]) 把字符数组转化为字符串
char[] a={'a','a','a','w'};

String d=new String(a);

//等同于

String d=new String("aaaw");
  1. String (char a[],int startIndex,int count) 从数组的startIndex开始,提取count个字符,生成字符串
char[] a={'a','a','a','w'};

String d=new String(a,2,2);

//等同于

String d=new String("aw");

1.4字符串的并置

String对象可以用 "+" 进行并置运算

String s1="qw"

string s2="er"

String s3="qwer"

当两个常量并置时,结果仍是常量,常量池没有则放入。

string s4="qw"+"er";

s4==s3//true

但参与并置的有一个是变量时,则会在动态区存放得到的实体和引用

String s5=s1+"er";

s5==s3//false

因为其相当于

String s5=new String("qwer");

1.5 String类的常用方法

  1. public int length() 获取字符序列的长度
String s1="qwer";

int i=s1.length();//i=4
  1. public boolean equals(string s) 比较字符序列是否与指定对象的相同

public boolean equalsIgnoreCase(String s)比较时忽略大小写

String s1="qwer";

String s2="qwer";

String s3="QWER";

System.out.println(s1.equals(s2));//true

System.out.println(s1.equalsIgnoreCase(s3));//true
  1. public boolean startsWith(String s), public boolean endsWith(String s)

检查字符串是否以刚定的序列开始或者结尾

String s1="qwer";

System.out.println(s1.startsWith("qw")); //true

System.out.println(s1.endsWith("r")); //true

注意即使判定的只有一个字符也要用双引号

  1. public int compareTo(String s)

按字典序与s比较大小,相同返回0 ,大于s返回正值,小于返回负值

String s1="abcd";

System.out.println(s1.compareTo("abcd"));

System.out.println(s1.compareTo("ab"));

System.out.println(s1.compareTo("abcde"));

s1.compareToIgnoreCase() 忽略大小写

  1. public boolean contains(String s)

判断对象是否包含序列s

String s1="abcd";

System.out.println(s1.contains("ab"));

System.out.println(s1.contains("abd"));

  1. public int indexOf(String s)和public int lastIndexOf(String s)

当前对象从序列0开始,s第一次出现的位置和最后一次出现的位置,没有检索返回-1.

indexOf(String s,int startpoint),从指定位置startpoint开始检索(包含startpoint)

String s1="abcd";

System.out.println(s1.indexOf("b",1));

  1. public String substring(int startpoint)

复制从startpoint开始的,产生一个新的对象

public String substring(int start,int end)

复制从start到end-1位置上的字符

String s1="abcdfsdfd";

System.out.println(s1.substring(2,4));

  1. public String trim() 返回去掉前后空格的序列
String s1=" ab df  d ";

System.out.println(s1.trim());

1.6 toString()

返回创建该对象类的名字@对象的引用的字符串表示

Dog a=new Dog();

System.out.println(a.toString());

Object的子类或间接子类可以重写该方法

2.StringBuffer

2.1StringBuffer介绍

String类对象的实体不可以改变,当修改字符时,实际修改的是引用。但StringBuffer类的对象的实体的内存可以改变,便于对字符的修改。

2.2构造方法

  • StringBuffer();

初始分配容量为16个字符,当实体存放的大于16时,实体容量自动增加,可以通过length()方法获取当前字符的个数,capacity()方法获取实际容量。

  • StringBuffer(int size);

通过指定size来分配其初始容量

  • StringBuffer(String s);

分配给s的字符序列长度再加16

StringBuffer a=new StringBuffer("qwe");

System.out.println(a.length());

System.out.println(a.capacity())

2.3 常用方法

  1. append方法
  • StringBuffer append(String s);

将s追加到当前序列中

  • StringBuffer append(int n);

将int型转化为String对象后追加

类似的还有long,boolean等类型

  1. public char charAt(int n);和public void setCharAt(int n,char ch);

第一个是返回位置n上的字符

第二个是将位置n上的字符用ch替换,n为非负数

  1. StringBuffer insert(int index,String str)

将str插入到指定位置index

  1. public StringBuffer reverse()

将字符序列翻转

  1. StringBuffer delete(int startIndex,int endIndex)

删除startIndex到endIndex-1的子序列

deleteCharAt(int index)

删除指定位置

  1. StringBuffer replace(int startIndex,int endIndex,String str)

将子序列用str替换,str长度不需要和替换掉的相同

StringBuffer a = new StringBuffer("qwe");

System.out.println(a.replace(0, 1, "sssss"));

3.StringBuilder

3.1StringBuilder简介

StringBuilder是一个可变的字符序列。此类提供一个与 StringBuffer 兼容的API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。

在大多数实现中,它比 StringBuffer 要快,因此建议优先采用该类。 在 StringBuilder 上的主要操作是 append 和 insert 方法。也具备自动扩容功能。StringBuilder类可以用于在无需创建一个新的字符串对象情况下修改字符串。StringBuilder不是线程安全的,而StringBuffer是线程安全的。但StringBuilder在单线程中的性能比StringBuffer高。因此合理选择使用。

3.2 常用方法

StringBuilder的常用方法和StringBuffer的一样。

3.3构造方法

StringBuilder() value内容为空,并设置容量为16个字节;

StringBuilder(CharSequece seq) 使用seq初始化,容量在此基础上加16;

StringBuilder(int capacity) 设置特定容量;

StringBuilder(String str) 使用str初始化,容量str大小的基础上加16;

4.三者区别

主要存在以下两个方面的区别:运行速度、线程安全。

4.1运行速度(执行速度)

运行速度的快慢:StringBuilder > StringBuffer > String。

4.2 线程安全

StringBuilder 是线程不安全的,而 StringBuffer 是线程安全的。

如果一个 StringBuffer 对象在字符串缓冲区被多个线程使用时,StringBuffer 中很多方法可以带有 synchronized 关键字,所以可以保证线程是安全的。但 StringBuilder 的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以在多线程环境下操作用 StringBuffer,在单线程环境下操作,还是建议使用速度比较快的 StringBuilder。

三、小结

  • 操作少量的字符串数据 用 String;
  • 单线程下字符缓冲区中的大量操作 用 StringBuilder(推荐使用);
  • 多线程下字符缓冲区中的大量操作 用 StringBuffer。