java中String 、 StringBuilder 和 StringBuffer的联系与区别

  String作为java中最基本的类,担负着承载字符信息的作用。String具有不可变的final属性 , 这也决定了它对于在程序中传递信息的不可或缺性 。开发中,我们常常要对字符串进行拼接,这时我们会用到String对象重载的“+”操作符或concat(str)方法,也可以用StringBuilder、StringBuffer对象的append(str)方法来实现。

那么,String、StringBuilder、StringBuffer之间到底有什么联系和区别?

什么情况下分别适合使用这三个不同的类?

使用中需要注意哪些问题呢?

一 、String

1 . String对象是不可变的 :String是个final类,所以它不可以被继承,它的值是不可改变的

2 . Sting对象不同的创建方式的区别:

  .class字节码文件在被JVM加载时,常量(符号引用、字符串字面量等)会在方法区的常量池中存放。其中,源码中出现过的字符串字面常量会保存在CONSTANT_STRING_INFO常量表中,根据不同创建方式,会有不同的内容分配

  1)字面常量方式创建的String变量   

1 String str1 = "abcd";
2 String str2 = "abcd";
3 System.out.println(str1==str2);//true

可见上面创建的两个String的引用str1和str2都指向了CONSTANT_STRING_INFO常量表中的(同一个拘留字符串)同一地址值,所以str1==str2返回true。这是因为该类在加载时,字符串常量被存放在CONSTANT_STRING_INFO常量表中,并且同一字面值的字符串常量只会保存一次(称为拘留字符串)。注意:这里并没有创建String对象,因为没有在堆中分配内存。

2)通过new关键字创建String对象

1 String str1 = new String("string");
2 String str2 = new String("string");
3 System.out.println(str1==str2);//false

此时,str1==str2返回false。首先,字节码在加载时,将“string”字符串常量存放到CONSTANT_STRING_INFO常量表中,所以上面语句中出现的“String”被放在常量表的同一位置;然后,在执行上面两条语句是,通过关键字new,分别在堆中创建了两个对象,并且两对象在堆中保存的值均为“string”;也就是说,内存中共有三处存有同一字符串值:常量表中的拘留字符串、str1指向的堆空间、str2指向的堆空间。

3)通过intern()方法创建的String“对象”

1 String str1 = new String("string");
2 String str2 = new String("string").intern();
3 System.out.pringln(str1==str2);//true

intern()方法的作用:1.当常量池中的字符串常量表中存在与“string”拘留字符串内容相同的字符串时,则直接返回这个拘留字符串地址值,赋值给str2,此时并没有创建新的对象;2.当常量池中的字符创常量表中没有“string”拘留字符串时,则把“string”添加到常量池并保存到字符串常量表中,成为拘留字符串,然后在堆中创建String对象并将对象的引用返回,此时有新的对象创建。此方法主要是为了避免重复创建字符串对象。

3 . String中重载 + 操作符的原理

我们都知道,在String重载的+操作符前后可以拼接其他内容,包括基本数据类型和引用数据类型,并且其他数据类型都会转化成String类型。

其实,重载+操作符实际上,都是创建了一个StringBuilder或StringBuffer对象,用append方法对字符串进行拼接,最后调用toString方法返回字符串。

需要注意 + 拼接字符串的两种情况 :

1 String str1 = "str";
2 String str2 = "ing";
3 String str = str1 + str2;
4 String str1_2 = "string";
5 System.out.pringln(str == str1_2);//false

这里 + 拼接的str1、str2是两个字符串变量,所以首先创建StringBuilder/StringBuffer对象,append(str1).append(str2)把str1和str2拼接起来,最后通过toString()生成一个新的String对象并把引用返回,赋值给str。这里创建了新的对象,所以会返回false;

1 String str1 = "str" + "ing";
2 String str2 = "string";
3 System.out.pringln(str1 == str2);//true

使用 + 操作符拼接两个字符串字面量时,JVM会自动将这两部分字符串合并成完整的字符串常量值,保存到常量池的字符串常量表中成为拘留字符串。所以,这里只是将拘留字符串返回了而已,并没有创建新的对象。

4 . String类的concat(str)方法拼接字符串

只能将String类型的内容拼接到调用者后面,并不能像重载的+ 操作符那样拼接其他数据类型的内容。

 1 public String concat(String str) {
 2   int otherLen = str.length();
 3   if (otherLen == 0) {
 4     return this;
 5     }
 6     char buf[] = new char[count + otherLen];
 7     getChars(0, count, buf, 0);
 8     str.getChars(0, otherLen, buf, count);
 9     return new String(0, count + otherLen, buf);
10}  

可以看到,concat(str)方法拼接字符串的原理是创建一个新的char[]字符数组,把两个字符串转化成char类型之后存放到数组中,最后用char[]数组创建一个新的String对象。

二 、StringBuilder

1 . StringBuilder是一个非线程安全的final类,不能被继承

2 . append(str)方法的原理

 1 public StringBuilder append(String str) {
 2     super.append(str);
 3     return this;
 4 }

调用了父类的append(str)方法:

 1   public AbstractStringBuilder append(String str) {
 2         if (str == null) {
 3             str = "null";
 4         }
 5         int len = str.length();
 6         if (len == 0) {
 7             return this;
 8         }
 9
10         int newCount = count + len;//统计拼接后字符串长度
11         if (newCount > value.length) {
12             expandCapacity(newCount);//如果拼接结果大于所用的char[],则扩容
13         }
14        //getChars将拼接字符串赋值到char[]中
15         str.getChars(0, len, value, count);
16         count = newCount;//更新char[]所保存的字符串长度
17         return this;
18     }

可知,用StringBuilder拼接字符串时,其实是在底层创建了一个char[]数组,然后通过char[]把要拼接的字符串添加到char[]而已。最后通过toString()生成最终拼接结果时就是通过  return new String(char[]) 实现的。

三 、StringBuffer

1 . StringBuffer是线程安全的final类,不能被继承

2 . append(str)方法

1 public synchronized StringBuffer append(String str) {
2     super.append(str);
3     return this;
4 }

可以看到,StringBuffer的append也是调用父类AbstractStringBuilder的append方法实现的,原理同StringBuilder。其唯一不同的地方在于,加了一个syncrhoized关键字修饰append()方法,保证了线程同步。

四 、String、StringBuilder和StringBuffer性能比较与选用

1 . 性能:StringBuilder > StringBuffer > String

  从上面四种(其实应该说是五种,+ 分为字符串常量的拼接和变量的拼接两种)的字符串拼接来看,除了字符串常量的拼接是返回拘留字符串的地址外,其他四种(str1+str2、str1.concat(str2)、builder.append(str1).append(str2)、buffer.append(str1).append(str2))都是使用了StringBuilder,或者说是StringBuilder的父类的拼接方法来做的——创建一个char数组,把需要拼接的内容先存进char数组,最后通过char数组创建新的String对象返回。

            造成三者性能差别的主要原因是:

  用String的 + 累加拼接字符串变量时,每拼接一个就会创建一个StringBuilder,并通过append()方法拼接,然后返回一个新的String对象。然后再继续拼接下一个变量。这样就会导致重复创建StringBuilder对象,性能低下。用 concat() 累计拼接时,则每两个字符串拼接都会创建一个 char[] 进行内容拼接并返回一个新的String对象作为结果,重复调用concat()会导致重复创建char[]和新String对象,性能低下。

  StringBuilder在调用toString()之前都不会创建拼接结果,并且底层的char数组会自动扩容,一直到拼接字符串全部存入char数组后,调用toString()时才创建新的String对象并返回,这样就避免了重复创建,效率提高。

  StringBuffer则因为使用了syncrhoized对append()进行了加锁,所以导致性能稍微低于StringBuilder。

2 . 不同情境下的选用

拼接两个字符串字面量,用 + 操作符;

单线程下拼接两个字符串变量,用StringBuilder;  

多线程下拼接两个字符串变量,用StringBuffer 。

原文地址:https://www.cnblogs.com/dingm/p/10505691.html

时间: 2024-10-13 01:31:25

java中String 、 StringBuilder 和 StringBuffer的联系与区别的相关文章

Java中String的两种赋值方式的区别

本文修改于:https://www.zhihu.com/question/29884421/answer/113785601 前言:在java中,String有两种赋值方式,第一种是通过"字面量"赋值,如:String str="hello",第二种是通过new关键字创建新对象,如:String str=new String("hello").那么这两种赋值的方式到底有什么区别呢,下面给出具体分析. 1.首先回顾Java虚拟机的结构图. 在上面的

Java中String两种不同创建方式的区别及intern的用法

一, Java有两种创建字符串的方式, String str1 = "abc"; String str2 = new String("abc"); 用双引号创建和用new来创建.这两种方式创建出来的String存储的位置上不同的.当使用双引号方式时,相当于显式的声明了字符串的值(字面值),所以是作为一个常量,存储在方法区的常量池中.使用new方式来创建String时,JVM会在堆上分配一块区域,存储一个String对象,值为“abc”. 二, String的==和e

Java中String的基础知识

Java中String的基础知识 ==与equal的区别 基本数据类型,指的是java中的八种基本数据结构(byte,short,char,int,long,float,double,boolean),一般的比较是使用的 ==,比较的是他们的值. 复合数据类型(类) ==比较的是两个对象的引用,可以理解为在内存中的地址,除非是同一个new出来的对象,他们的 ==为true,否则,都为false. equal是object中的方法.object中的实现如下,内部还是使用==实现,也就是说,如果一个

JAVA中 String 、StringBuffer和StringBuilder 的区别

String 内容定义成 final char[],只能在属性和构造函数中赋值,其它地方不能改变 :String 覆盖实现了 equals . StringBuffer 内容定义成了 char[] ,但没实现 equals. String 和 StringBuffer 的区别是: 1.String 通过构造新的String 实现可变字符串,而 StringBuffer 通过改变内部的内容属性来实现可变字符串. 2.new String("ABC").equals("ABC&q

java中String、StringBuffer、StringBuilder的区别

java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可变 String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的. private final char value[]; StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在Abstra

Java基础——java中String、StringBuffer、StringBuilder的区别

(转自:http://www.cnblogs.com/xudong-bupt/p/3961159.html) java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可变 String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的. private final char value[]; Strin

java中String、StringBuffer、StringBuilder的总结

看了很多关于java的string的相关知识,这里做一个较为全面的总结,内容转自不同地方的博客,鉴于出处较多,就不一一列举了. java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 1.可变与不可变 String类中使用字符数组保存字符串

探秘Java中String、StringBuilder以及StringBuffer

探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String.StringBuilder和StringBuffer这几个类,分析它们的异同点以及了解各个类适用的场景.下面是本文的目录大纲: 一.你了解String类吗? 二.深入理解String.StringBuffer.StringBuilder 三.不同场景下三个类的性能测试 四.常见的关于

Java中String,StringBuffer和StringBuilder的区别(转载)

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简 要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了

java中String类、StringBuilder类和StringBuffer类详解

本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html 版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利 正文: 探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得