ArrayList转化为数组

java.util.ArrayList提供了两个方法:

// method#1
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}
// method#2
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}
// referenced method by method#2
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    // 构造一个对应数据类型的新数组
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    // 拷贝数据
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

// 测试代码
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(1);al.add(2);
Integer[] arr = new Integer[al.size()];
// arr = (Integer[])al.toArray(); // Java不能一次性强制转化数组中每个元素类型
al.toArray(arr); //这是Java提供的解决方法

equals() vs hashCode()

HashMap HashSet

HashSet 是基于HashMap的,即HashSet是值都是private static final Object PRESENT = new Object();的HashMap

HashMap中迭代器每次都要遍历table找下一个key,但考虑装载因子大概0.75,所以遍历的空值不会太多而影响效率

final Entry<K,V> nextEntry() {
  if (modCount != expectedModCount)
      throw new ConcurrentModificationException();
  Entry<K,V> e = next;
  if (e == null)
      throw new NoSuchElementException();
  
  //先判断冲突链上是否有后续元素
  if ((next = e.next) == null) {
      Entry[] t = table;
      // 遍历table,找到下一个key
      while (index < t.length && (next = t[index++]) == null)
          ;
  }
  current = e;
  return e;
}

HashMap使用chain的方式解决冲突

java.lang.String.hashCode()

public int hashCode() {
    int h = hash;
    if (h == 0 && count > 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

IO流同步问题 TODO

序列化

transient: The transient keyword in Java is used to indicate that a field should not be serialized.

ArrayList序列化,存放数据的数组被声明为transient的,之后重写了序列化规则(writeObject(), readObject()),至于为啥要声明为transient,可能是对开发者的特别提示吧

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

    ....

StringBuffer扩容

代码如下,很简洁,其他容器类扩容方式不尽相同,比如HashMap等哈希容器,需要保证长度是2的幂指数

public AbstractStringBuilder append(String str) { 
    if (str == null) str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}

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);
}

Java Regex AppendReplacement

Matcher.quoteReplacement(String replacement): literalize replacement, slash(‘/’) or dollar(‘$’) with no special meanings.

public static String updateCharsetValue(String file, Charset charset) {
    Matcher match = GenericCharsetPatt.matcher(file);
    StringBuffer nHtml = new StringBuffer();
    String pre, post;
    while (match.find()) {
        pre = match.group(1);
        post = match.group(3);
        match.appendReplacement(nHtml, Matcher.quoteReplacement(pre
            + charset.displayName() + post));
    }
    match.appendTail(nHtml);
    return nHtml.toString();
}

java.lang.Object

  1. 好多方法都是native的,即调用的虚拟机的底层语言,一般为c++
  2. clone方法是一个‘浅拷贝’,我的理解是对象中的所有域做了‘值拷贝’:
    1. 对象中的域分三种:primitive,不变对象(final的,如字符串),普通对象
    2. 对于primitive和不变对象进行‘值’拷贝是没有任何问题的,因为它们是不会变的
    3. 对于普通对象的‘值’拷贝,相当于只拷贝了引用,但指向的都是同一个实际对象
TOP