String StringBuffer和StringBuilder

一、总述

String是字符串常量,StringBuffer和StringBuilder是字符串变量;StringBuffer线程安全而StringBuilder是不安全的

二、String与两者的区别

String:

  1 public final class String
  2     implements java.io.Serializable, Comparable<String>, CharSequence {
  3     private final char value[];
  4 }
  5 

String是不可变类,由final修饰,其底层结构char[ ]也是final,并且其中每个方法都没有对value的内容进行改动,一旦创建就不可修改。

  1 String a = "idea";
  2 a = a+"good";

如a = "good"+a,并不是在a的原地址上修改,而是创建了一个新的"ideagood"对象,并把引用给a。

StringBuffer和StringBuilder:

  1 public final class StringBuffer extends AbstractStringBuilder
  2     implements java.io.Serializable, CharSequence

 

  1 public final class StringBuilder extends AbstractStringBuilder
  2     implements java.io.Serializable, CharSequence
  3 

StringBuffer和StringBuilder都继承自AbstractStringBuilder。

  1 abstract class AbstractStringBuilder implements Appendable, CharSequence {
  2    char[] value;
  3 }
  4 

其底层char[ ]数组并未被final修饰是字符串变量,上述a = "good"+a,实际操作为a = new StringBuffer(a).append("good").toString,它的修改是在原地址上进行的。

三、StringBuffer和StringBuilder区别

AbstractStringBuilder的append方法,ensureCapacityInternal( )函数会对char[ ]数组容量进行校验,不够会进行扩容:

  1  public AbstractStringBuilder append(char[] str) {
  2     int len = str.length;
  3     ensureCapacityInternal(count + len);
  4     System.arraycopy(str, 0, value, count, len);
  5     count += len;
  6     return this;
  7 }

StringBuffer的所有public方法均采用Sychronized修饰,因此线程安全,但相比之下效率低于StringBuilder

  1 @Override
  2 public synchronized StringBuffer append(char[] str) {
  3    toStringCache = null;
  4    super.append(str);
  5    return this;
  6 }

StringBuilder直接使用父类方法,不具备线程安全,但单线程下效率可观

  1 @Override
  2 public StringBuilder append(char[] str) {
  3    super.append(str);
  4    return this;
  5 }
  6 

四、HashSet的唯一性问题

Set接口存入对象具有唯一性,但也存在问题:

  1  HashSet<StringBuilder> set2 = new HashSet<>();
  2 StringBuilder sb1 = new StringBuilder("abc");
  3 StringBuilder sb2 = new StringBuilder("abc");
  4 System.out.println(sb1 == sb2);//false
  5 
  6 set2.add(sb1);
  7 set2.add(sb2);
  8 
  9 Iterator<StringBuilder> it2 = set2.iterator();
 10 while (it2.hasNext())
 11 System.out.println(it2.next());//"abc"   "abc

sb1和sb2内容相同的不同对象,HashSet存入两个相同的值,打破了唯一性;

  1 HashSet<String> set1 = new HashSet<>();
  2 String s1 = new String("abc");
  3 String s2 = "abc";
  4 System.out.println(s1 == s2);//"false"
  5 set1.add(s1);
  6 set1.add(s2);
  7 Iterator<String> it1 = set1.iterator();
  8 while (it1.hasNext())
  9 System.out.println(it1.next());//"abc"

s1和s2内容相同的不同对象,但set中只存入了一个值。

原因:HashSet底层是HashMap,而HashMap对对象的判断:

  1 if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))
  2     break;

是通过hashcode和equals( )方法,String重写了hash函数和equals方法,不再是根据对象地址进行计算和判断,而是根据对象内容进行计算,因此s1和s2虽然地址不同,但hashcode相同,equals为true。而StringBuilder没有重写这两个方法,因此sb1和sb2尽管内容相同,因为地址不同,所以hashcode不同,equals为false。

  1 public boolean equals(Object anObject) {
  2     if (this == anObject) {
  3           return true;
  4     }
  5     if (anObject instanceof String) {
  6          String anotherString = (String)anObject;
  7          int n = value.length;
  8          if (n == anotherString.value.length) {
  9               char v1[] = value;
 10               char v2[] = anotherString.value;
 11               int i = 0;
 12               while (n-- != 0) {
 13                   if (v1[i] != v2[i])
 14                       return false;
 15                   i++;
 16              }
 17               return true;
 18           }
 19        }
 20        return false;
 21   }
equals
  1 public int hashCode() {
  2    int h = hash;
  3    if (h == 0 && value.length > 0) {
  4         char val[] = value;
  5         for (int i = 0; i < value.length; i++) {
  6               h = 31 * h + val[i];
  7             }
  8         hash = h;
  9     }
 10     return h;
 11 }
hashCode
posted @ 2020-04-25 16:04  Aidan_Chen  阅读(145)  评论(0编辑  收藏  举报