标签:java
一,String,StringBuilder和StringBuffer的区别
同:三者都是final类,主要操作对象都是char[]
异:
1,继承结构,String继承自Object,实现了Serializable,Comparable,CharSequence,而StringBuilder和StringBuffer的父类是AbstractStringBuilder,实现接口Serializable, CharSequence;
2,在操作字符串时,String的"+"编译后会是new StringBuider(str)再.append(otherStr),最后把StringBuilder对象返回,在反编译文件中非常明显,而StringBuilder和StringBuffer的append方法,最后都是调用父类AbstracStringBuilder的append(String str)方法;
例如:
static String getStr(){ return "abc"; } public static void main(String[] args) { String dist = "hello "; String tmp = dist + getStr(); }编译后是:
static String getStr() { return "abc"; } public static void main(String args[]) { String dist = "hello "; String tmp = (new StringBuilder(String.valueOf(dist))).append(getStr()).toString(); }
3,线程同步问题,由于String的"+"是和StringBuilder操作字符串的方式一致,从源代码看,StringBuilder的append方法不是线程安全,所以String和StringBuilder对字符串的操作不是线程安全,而StringBuiffer是线程安全。
源代码StringBuilder:
@Override public StringBuilder append(String str) { super.append(str); return this; }源代码StringBuffer:
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
4,效率问题,
a,在编译时可以确定字符对象的情况下,编译器会将"+"两边的字符串拼接后作为一个常量,不管是String+,还是StringBuilder().append(stri1+str2),这种情况下,String+的代码效率是最高的,因为jvm只需要操作常量池中的一个对象;
例如:
String tmp4 = "a" + "b" + "c"; System.out.println(tmp4);编译后,在class文件中反编译过来是这样的:
String tmp4 = "abc"; System.out.println(tmp4);
b,在编译时不能确定字符对象的情况下,尽量用StringBuilder或者StringBuffer,如果有线程安全问题,采用StringBuffer,并且在创建StringBuffer和StringBuilder对象时,要注意传给构造器参数,在父类AbstractStringBuilder的类中,有一个构造器AbstractStringBuilder(int capacity),这个capacity对效率的影响非常大,默认是16,如果append()的字符长度超过了16,会capacity = << 1,即是16左移1位,新建一个容量capacity 为32的对象,再把之前的已经填满的char[16]的数组拷贝到新对象的前面16个下标中,然后再append后面的数据。所以,如果capacity 太小,会造成多次的resize,这个动作很费资源。
StringBuilder和StringBuffer构造器的源代码:
/** * 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} argument. * * @param capacity the initial capacity. * @throws NegativeArraySizeException if the {@code capacity} * argument is less than {@code 0}. */ public StringBuilder(int capacity) { super(capacity); }
AbstractStringBuilder的构造器:
/** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; }
append方法和那个resize的方法:
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; } void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); }
1,继承结构,都实现了Map接口,Cloneable和Serializable接口,但是HashMap继承自AbstractMap,Hashtable继承自Dictionary,从继承结构来看,Hashtable多了两个从Dictionary继承的方法keys和elements;
2,HashTable是线程安全的,HashMap是非线程安全;
3,HashMap可以有一个key为null,值任意,Hashtable不允许key为null
4,如果key存在,table不会覆盖旧值,map则会覆盖。
5,HashMap的set是一个TreeNode,HashTable是一个Synchornize
标签:java
原文地址:http://blog.csdn.net/zranye/article/details/41637283