String类、StringBuilder、StringBuffer

String

特点:

  • 字符串的内容是用不可变的
  • 字符串是常量,是可以共享使用的
  • 字符串效果上相当于是char[]字符数组,但是底层原理是byte[]字节数组

        String类的一个最大特性是不可修改性,而导致其不可修改的原因是在String内部定义了一个char类型的常量数组,因此每次对字符串的操作实际上都会另外分配一个新的常量数组空间(这片空间位于jvm的方法区)。

三种构造方法:

1、创建一个空白字符串,不含有任何内容。
public String():
  String str = new String();

2、根据字符数组的内容,来对应的字符串。
public String(char[] array):
  char[] charArray = {'A','B','C'};
  String str = new String(charArray);

3、根据字节数组的内容,来对应的字符串。
public String(byte[] array):
  byte[] byteArray = {33,55,77};
  String str = new String(byteArray)

一种直接创建:

String str = "CaiNiap";//右边直接用双引号

程序当中直接写上的双引号字符串,就在字符串常量池中。

String str=“abc”和 String str =new String(“abc”)的区别

1. String str=“abc”;

      “abc”存放在常量池中。

2.String str =new String(“abc”);

      单纯的在堆内存中new一个String对象,通过StringBuilder 跟StringBuffer 构建的对象也是一样。

例子:

String str1 = "abc";
String str2 = "abc"; 
System.out.println(str1==str2); 
System.out.println("====================分割线====================================="); String str3 = new String("abc"); 
String str4 = new String("abc"); 
System.out.println(str3==str4);

结果:

1. String str=“abc”;

 2.String str =new String(“abc”);

常用方法

  1. int length()----返回此字符串的长度。

  2. char charAt(int index)---根据下标获取字符串的某个字符(可以获取某个特定位置的字符)。

  3. String concat(String str)----将指定字符串连接到此字符串的结尾(相当于“+”运算符)

  4. boolean contains(CharSequence s)----判断此char值序列s是否在字符串中,存在返回true(可以判断此字符串是否存在某个子串)

  5. boolean endWith(String suffix)----判断此字符串是否以指定的后缀结束

  6. boolean startWith(String perfix)----判断此字符串是否以指定的前缀开始

  7. booean equals(Object anObject)----将此字符串与指定的字符串进行比较(这个方法是重写了String的父类Object的方法,用来判断两个字符串的值是否相同)

  8. boolean equalsIgnoreCase(String anotherString)----将此字符串和另一个字符串进行比较,不考虑大小写

  9. String format(String format,Object... args)---字符串进行格式化输出

  10. int indexOf(string str) :返回第一次出现的指定子字符串在此字符串中的索引。不存在指定字符,返回-1

  11. int indexOf(string str, int startIndex) : 从指定的索引处开始,返回第一次出现的指定子字符串在此字符串中的索引。

  12. String intern()----返回字符串对象的规范化表示形式

  13. boolean isEmpty()----当且仅当length()为0时返回true

  14. int lastIndexOf(String str)----返回指定字符串在此字符串中最后一次出现的索引。

  15. boolean matches(String regex)----判断此字符串是否匹配给定的正则表达式

  16. String replace(char oldChar,char newChar)----替换字符串,

    public static void main(String args[]) {
            String Str = new String("hello");
            System.out.println(Str.replace('o', 'T'));  // o被替换成T
        }
  17. String[] split(String regex)----根据给定的正则表达式来拆分此字符串

  18. String substring(int beginIndex,int endIndex)----字符串截取,从beginIndex索引截取到endIndex处

  19. char[] toCharArray()----把此字符串转换成一个新的char数组

  20. String toLowerCase()----把此字符串中的所有字符都转换为小写

  21. String toUpperCase()----把此字符串中的所有字符都转换为大写

  22. String toString()----用字符串的形式来返回此对象本身(它已经是一个字符串)

  23. Static String valueOf(int i)----返回int参数的字符串形式(也就是所谓的类型转换,相应的还有其他基础数据类型的,比如boolean,double,long,char)

StringBuilder与StringBuffer

        简要的说,String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

        而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做

在大部分情况下 StringBuffer > String
StringBuffer(线程安全)
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer

StringBuilde(线程不安全)
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

字符串的拼接

常见的四种字符串拼接方法分别是:

  • 1.直接用“+”号
  • 2.使用String的方法concat
  • 3.使用StringBuilder的append
  • 4.使用StringBuffer的append

1. 加号拼接

打开编译后的字节码我们可以发现加号拼接字符串jvm底层其实是调用StringBuilder来实现的,也就是说”a” + “b”等效于下面的代码片。

String a = "a";
StringBuilder sb = new StringBuilder();
sb.append(a).append("b");
String str = sb.toString();

但并不是说直接用“+”号拼接就可以达到StringBuilder的效率了,因为用“+”号每拼接一次都会新建一个StringBuilder对象,并且最后toString()方法还会生成一个String对象。在循环拼接十万次的时候,就会生成十万个StringBuilder对象,十万个String对象,这简直就是噩梦。

2.concat拼接

concat的源代码如下,可以看到,concat其实就是申请一个char类型的buf数组,将需要拼接的字符串都放在这个数组里,最后再转换成String对象。

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

3.StringBuilder/StringBuffer

这两个类实现append的方法都是调用父类AbstractStringBuilder的append方法,只不过StringBuffer是的append方法加了sychronized关键字,因此是线程安全的。

实验

代码如下:

public static void main(String[] args) {
        long starTime = new Date().getTime();
        String string = new String();
        for (int i = 0; i < 50000; i++) {
            string = string + i;
        }
        long endTime = new Date().getTime();
        System.out.println("“+”号花费时间:" + (endTime - starTime));

        long starTime1 = new Date().getTime();
        String string1 = new String();
        for (int i = 0; i < 50000; i++) {
            string1 = string1.concat(String.valueOf(i));
        }
        long endTime1 = new Date().getTime();
        System.out.println("concat花费时间:" + (endTime1 - starTime1));

        long starTime2 = new Date().getTime();
        String string2 = new String();
        StringBuffer stringb = new StringBuffer();
        for (int i = 0; i < 50000; i++) {
            stringb = stringb.append(i);
        }
        string2 = string2 + stringb;
        long endTime2 = new Date().getTime();
        System.out.println("StringBuffer花费时间:" + (endTime2 - starTime2));

    }

运算结果:

“+”号花费时间:7122
concat花费时间:1939
StringBuilder花费时间:10

1.大量拼接字符串
通过实验我们发现,在循环拼接同一个字符串的时候,他们效率的按快慢排序是
StringBulider > StringBuffer >> String.concat > “+”。
StringBulider比StringBuffer更快这个容易理解,因为StringBuffer的方法是sychronized修饰的,同步的时候会损耗掉一些性能。StringBulider和String.concat的区别,主要在扩容上,String.concat是需要多少扩多少,而StringBulider是每次翻两倍,指数级扩容。在10万次拼接中,String.concat需要扩容10万次,而StringBuilder只需要扩容log100000次(大约17次),除此之外,concat每次都会生成一个新的String对象,而StringBuilder则不必,那StringBuilder如此快就不难解释了。至于直接用“+”号连接,之前已经说了,它会产生大量StringBuilder和String对象,当然就最慢了。
2.少量字符串拼接
在只拼接少量字符串的情况下的时候,他们效率的按快慢排序是
String.concat > StringBulider > StringBuffer > “+”。
为什么在拼接少量字符串的时候,String.concat就比StringBuilder快了呢,原因大致有两点,一是StringBuilder的调用栈更深,二是StringBuilder产生的垃圾对象更多,并且它重写的toString方法为了做到不可变性采用了“保护性拷贝”,因此效率不如concat。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值