您的位置:首页 > 产品设计 > UI/UE

java面试题String,StringBuilder,StringBuffer

2017-02-20 14:10 417 查看
     面试的经历中,相信大家都经常被问到这三者的区别,说到String我相信绝大多数的人都会说:"String是不可变的,final修饰的",你会看到面试官微微猥琐一笑,接着问到:“final修饰的类就是不可变的吗,那StringBuilder和StringBuffer不是final修饰的?”

1. 先来说说String

看下JDK1.7 String成员变量的源码

[java]
view plain
copy





/** 
 * @author  Lee Boynton 
 * @author  Arthur van Hoff 
 * @author  Martin Buchholz 
 * @author  Ulf Zibis 
 * @see     java.lang.Object#toString() 
 * @see     java.lang.StringBuffer 
 * @see     java.lang.StringBuilder 
 * @see     java.nio.charset.Charset 
 * @since   JDK1.0 
 */  
  
public final class String  
    implements java.io.Serializable, Comparable<String>, CharSequence {  
    /** The value is used for character storage. */  
    private final char value[];  
  
    /** Cache the hash code for the string */  
    private int hash; // Default to 0  
  
    /** use serialVersionUID from JDK 1.0.2 for interoperability */  
    private static final long serialVersionUID = -6849794470754667710L;  

可以看到String定义的成员变量value和hash,其中value是个字节数组,而且是final修饰,这个才是String不可变的关键点;

JDK1.7 String的部分注解

[java]
view plain
copy





The Java language provides special support for the string  
* concatenation operator ( + ), and for conversion of  
* other objects to strings. String concatenation is implemented  
* through the <code>StringBuilder</code>(or <code>StringBuffer</code>)  
* class and its <code>append</code> method.  
* String conversions are implemented through the method  
* <code>toString</code>, defined by <code>Object</code> and  
* inherited by all classes in Java. For additional information on  
* string concatenation and conversion, see Gosling, Joy, and Steele,  
* <i>The Java Language Specification</i>.  

上面解释了java为String提供了特殊的支持,例如:String a="a";  String b="b" ;当执行String c=a+b操作时,实际上是创建一个StringBuilder对象,再通过apend()进行拼接,最后调用toStirng()生成一个新的对象给c。

String提供修改内容的方法最终都是调用new String()。看下 String的部分注解

[java]
view plain
copy





/**  
 * The <code>String</code> class represents character strings. All  
 * string literals in Java programs, such as <code>"abc"</code>, are  
 * implemented as instances of this class.  
 * <p>  
 * Strings are constant; their values cannot be changed after they  
 * are created. String buffers support mutable strings.  
 * Because String objects are immutable they can be shared. For example:  
 * <p><blockquote><pre>  
 *     String str = "abc";  
 * </pre></blockquote><p>  
 * is equivalent to:  
 * <p><blockquote><pre>  
 *     char data[] = {'a', 'b', 'c'};  
 *     String str = new String(data);  
 * </pre></blockquote><p>  
 * Here are some more examples of how strings can be used:  

这里定义了一个String str = "abc";相当于char data[] = {'a', 'b', 'c'};String str = new String(data);

再来看一个substring()方法的源码

[java]
view plain
copy





/** 
     * Returns a new string that is a substring of this string. The 
     * substring begins at the specified <code>beginIndex</code> and 
     * extends to the character at index <code>endIndex - 1</code>. 
     * Thus the length of the substring is <code>endIndex-beginIndex</code>. 
     * <p> 
     * Examples: 
     * <blockquote><pre> 
     * "hamburger".substring(4, 8) returns "urge" 
     * "smiles".substring(1, 5) returns "mile" 
     * </pre></blockquote> 
     * 
     * @param      beginIndex   the beginning index, inclusive. 
     * @param      endIndex     the ending index, exclusive. 
     * @return     the specified substring. 
     * @exception  IndexOutOfBoundsException  if the 
     *             <code>beginIndex</code> is negative, or 
     *             <code>endIndex</code> is larger than the length of 
     *             this <code>String</code> object, or 
     *             <code>beginIndex</code> is larger than 
     *             <code>endIndex</code>. 
     */  
    public String substring(int beginIndex, int endIndex) {  
        if (beginIndex < 0) {  
            throw new StringIndexOutOfBoundsException(beginIndex);  
        }  
        if (endIndex > value.length) {  
            throw new StringIndexOutOfBoundsException(endIndex);  
        }  
        int subLen = endIndex - beginIndex;  
        if (subLen < 0) {  
            throw new StringIndexOutOfBoundsException(subLen);  
        }  
        return ((beginIndex == 0) && (endIndex == value.length)) ? this  
                : new String(value, beginIndex, subLen);  
    }  

看完这些,你可以清楚的知道定义一个变量str="hello world",则是在内存中分配一个对象new String("hello world"),当你修改str="hello nimei",变量重新指向内存中新分配的new String("hello nimei");原来内存中的new String("hello world")还在那里,没有改变,等待垃圾回收。难道真的没有办法修改new
String("hello world")对象中的值而不重新在内存中重新new一次吗?让我们来看看一个例子。



原来通过反射可以修改String对象中的内容,反射太强大了。

2.StringBuffer和StringBuilder

StringBuffer的部分源码

[java]
view plain
copy





* @author      Arthur van Hoff  
 * @see     java.lang.StringBuilder  
 * @see     java.lang.String  
 * @since   JDK1.0  
 */  
 public final class StringBuffer  
    extends AbstractStringBuilder  
    implements java.io.Serializable, CharSequence  
{  
  
    /** use serialVersionUID from JDK 1.0.2 for interoperability */  
    static final long serialVersionUID = 3388685877147921107L;  
  
    /** 
     * Constructs a string buffer with no characters in it and an 
     * initial capacity of 16 characters. 
     */  
    public StringBuffer() {  
        super(16);  
    }  
  
    /** 
     * Constructs a string buffer with no characters in it and 
     * the specified initial capacity. 
     * 
     * @param      capacity  the initial capacity. 
     * @exception  NegativeArraySizeException  if the <code>capacity</code> 
     *               argument is less than <code>0</code>. 
     */  
    public StringBuffer(int capacity) {  
        super(capacity);  
    }  
  
    /** 
     * Constructs a string buffer initialized to the contents of the 
     * specified string. The initial capacity of the string buffer is 
     * <code>16</code> plus the length of the string argument. 
     * 
     * @param   str   the initial contents of the buffer. 
     * @exception NullPointerException if <code>str</code> is <code>null</code> 
     */  
    public StringBuffer(String str) {  
        super(str.length() + 16);  
        append(str);  
    }  

StringBuilder的部分源码

[java]
view plain
copy





* @author      Michael McCloskey  
 * @see         java.lang.StringBuffer  
 * @see         java.lang.String  
 * @since       1.5  
 */  
public final class StringBuilder  
    extends AbstractStringBuilder  
    implements java.io.Serializable, CharSequence  
{  
  
    /** use serialVersionUID for interoperability */  
    static final long serialVersionUID = 4383685877147921099L;  
  
    /** 
     * Constructs a string builder with no characters in it and an 
     * initial capacity of 16 characters. 
     */  
    public StringBuilder() {  
        super(16);  
    }  
  
    /** 
     * Constructs a string builder with no characters in it and an 
     * initial capacity specified by the <code>capacity</code> argument. 
     * 
     * @param      capacity  the initial capacity. 
     * @throws     NegativeArraySizeException  if the <code>capacity</code> 
     *               argument is less than <code>0</code>. 
     */  
    public StringBuilder(int capacity) {  
        super(capacity);  
    }  
  
    /** 
     * Constructs a string builder initialized to the contents of the 
     * specified string. The initial capacity of the string builder is 
     * <code>16</code> plus the length of the string argument. 
     * 
     * @param   str   the initial contents of the buffer. 
     * @throws    NullPointerException if <code>str</code> is <code>null</code> 
     */  
    public StringBuilder(String str) {  
        super(str.length() + 16);  
        append(str);  
    }  

StringBuffer和StringBuilder的这部分源码基本一样,构造函数初始化大小都为16,都是继承了AbstractStringBuilder。

看看AbstractStringBuilder定义成员变量的源码

[java]
view plain
copy





/** 
 * A mutable sequence of characters. 
 * <p> 
 * Implements a modifiable string. At any point in time it contains some 
 * particular sequence of characters, but the length and content of the 
 * sequence can be changed through certain method calls. 
 * 
 * @author      Michael McCloskey 
 * @author      Martin Buchholz 
 * @author      Ulf Zibis 
 * @since       1.5 
 */  
abstract class AbstractStringBuilder implements Appendable, CharSequence {  
    /** 
     * The value is used for character storage. 
     */  
    char[] value;  
  
    /** 
     * The count is the number of characters used. 
     */  
    int count;  
  
    /** 
     * This no-arg constructor is necessary for serialization of subclasses. 
     */  
    AbstractStringBuilder() {  
    }  
  
    /** 
     * Creates an AbstractStringBuilder of the specified capacity. 
     */  
    AbstractStringBuilder(int capacity) {  
        value = new char[capacity];  
    }  

AbstractStringBuilder中定义的变量value,是个字节数组,和String的成员变量value相比,String的value是final修饰的,所以StringBuffer和StringBuilde的内容可以变。

在对比下StingBuffer和StringBuilder的实现其他细节,以append()方法为例。

[java]
view plain
copy





public synchronized StringBuffer append(String str) {  
       super.append(str);  
       return this;  
   }  

[java]
view plain
copy





public StringBuilder append(String str) {  
      super.append(str);  
      return this;  
  }  

两者最大的区别是:StingBuffer所有的实现的方法都是sychronized修饰的,StringBuilder则不是。

2.String、StringBuffer和StringBuilder的总结

1).  String和StringBuffer、StringBuilder相比,String是不可变的,String的每次修改操作都是在内存中重新new一个对象出来,而StringBuffer、StringBuilder则不用,并且提供了一定的缓存功能,默认16个字节数组的大小,超过默认的数组长度时,则扩容为原来字节数组的长度*2+2。

2).  StringBuffer和StringBuilder相比,StringBuffer是synchronized的,是线程安全的,而StringBuilder是非线程安全的,单线程情况下性能更好一点;使用StringBuffer和StringBuilder时,可以适当考虑下初始化大小,较少扩容的次数,提高代码的高效性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息