一,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);
}
二,HashMap和HashTable的区别?
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