-
- 2014-05-05
- 英语
学习英语第十周至第十一周
阅读英文原著
Book Time Progress Harry Potter And The Goblet of Fire 2014.04.21 ~ 2014.05.04 312/734 -
- 2014-05-05
学习英语第十周至第十一周
标签:英语
阅读英文原著
Book Time Progress Harry Potter And The Goblet of Fire 2014.04.21 ~ 2014.05.04 312/734 -
- 2014-05-12
- 英语
学习英语第十二周
标签:英语
阅读英文原著
Book Time Progress Harry Potter And The Goblet of Fire 2014.05.05 ~ 2014.05.11 732/734 -
- 2014-05-21
OpenJDK 源码阅读之 LinkedList
定义
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { }
盲点
- serialVersionUID
private static final long serialVersionUID = 876323262645176354L;
序列化版本号,如果前一版本序列化后,后一版本发生了很大改变,就使用这个号告诉虚拟机,不能反序列化了。
问题
- writeObject
比例一下
ArrayList
与LinkedList
中的 writeObjectprivate void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // Write out element count, and any hidden stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out array length s.writeInt(elementData.length); // Write out all elements in the proper order. for (int i=0; i<size; i++) s.writeObject(elementData[i]); if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out size s.writeInt(size); // Write out all elements in the proper order. for (Node<E> x = first; x != null; x = x.next) s.writeObject(x.item); }
注意后者没有检查
modCount
,这是为什么呢?之前看ArrayList
的时候觉得是为线程安全考虑的,可是现在为什么又不检查了呢?虽然两个文件的注释中都说到,如果有多个线程操作此数据结构,应该从外部进行同步。但是一个检查,一个不检查是几个意思呀?思考
- 维护数据结构一致性
private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
注意代码第
5
行对f
的检查,6
行对last
的调整。一定要细心,保证操作后,所有可能
涉及的数据都得到相应更新。- 隐藏实现
public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; }
注意返回的是数据,而不是
Read More ...Node
,外部根本不需要知道Node
的存在。 另外,为什么f == null
要抛出异常而不是返回null
? -
- 2014-05-22
OpenJDK 源代码阅读之 HashSet
概要
- 类继承关系
java.lang.Object java.util.AbstractCollection<E> java.util.AbstractSet<E> java.util.HashSet<E>
- 定义
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
- 要点
- 不保证元素次序,甚至不保证次序不随时间变化
- 基本操作(add, remove, contains, size)常量时间
- 迭代操作与当前元素个数加底层容量大小成正比
- 不保证同步
思考
- 总体实现
底层是用
HashMap
实现的,Set
中的数据是HashMap
的key
,所有的key
指向同一个value
, 此value
定义为:// Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
再看一下
add
,大概就能明白了/** * Adds the specified element to this set if it is not already present. * More formally, adds the specified element <tt>e</tt> to this set if * this set contains no element <tt>e2</tt> such that * <tt>(e==null ? e2==null : e.equals(e2))</tt>. * If this set already contains the element, the call leaves the set * unchanged and returns <tt>false</tt>. * * @param e element to be added to this set * @return <tt>true</tt> if this set did not already contain the specified * element */ public boolean add(E e) { return map.put(e, PRESENT)==null; }
- load factor
public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
初始化中,注意使用的
Read More ...HashMap
的 load factor 设置为 0.75,如果太小,就设置成 16. 为什么要 0.75 呢? 有什么依据吗? -
- 2014-05-23
OpenJDK 源代码阅读之 String
概要
- 类继承关系
java.lang.Object java.lang.String
- 定义
public final class String extends Object implements Serializable, Comparable<String>, CharSequence
- 要点
一旦创建就不可改变
实现
- storage
/** The value is used for character storage. */ private final char value[];
可以看出
String
中的数据是如何存储的。- 初始化
public String(String original) { this.value = original.value; this.hash = original.hash; }
可以看出使用
String
类型初始化,新String
实际上与原来的String
指向同一块内存。public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
如果用
char[]
初始化,可以看出,新分配了内存,并复制,保证了两者相互独立,只是内容相同。public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } }
注意用
StringBuffer
初始化时,对同一buffer
是线程安全的,即初始化String
的过程中,其它线程不会改变buffer
的内容。另外,能告诉我下面这段代码是怎么回事么?
public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }
为啥这次不同步了呢?
Read More ... -
- 2014-05-24
OpenJDK 源码阅读之 ArrayList
概要
- 类继承关系
java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java.util.ArrayList<E>
- 定义
Read More ...public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { }
-
- 2014-05-25
- 英语
学习英语第十三十四周
标签:英语
阅读英文原著
Book Time Progress Harry Potter And The Goblet of Fire 2014.05.12 ~ 2014.05.23 734/734 -
- 2014-05-25
OpenJDK 源代码阅读之 HashMap
概要
- 类继承关系
java.lang.Object java.util.AbstractMap<K,V> java.util.TreeMap<K,V>
- 定义
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, Serializable
- 要点
1) 与 Hashtable 区别在于:非同步,允许
Read More ...null
2) 不保证次序,甚至不保证次序随时间不变 3) 基本操作 put, get 常量时间 4) 遍历操作 与 capacity+size 成正比 5) HashMap 性能与capacity
和load factor
相关,load factor
是当前元素个数与capacity
的比值,通常设定为0.75
,如果此值过大,空间利用率高,但是冲突的可能性增加,因而可能导致查找时间增加,如果过小,反之。当元素个数大于capacity * load_factor
时,HashMap
会重新安排 Hash 表。因此高效地使用HashMap
需要预估元素个数,设置最佳的capacity
和load factor
,使得重新安排 Hash 表的次数下降。 -
- 2014-05-26
OpenJDK 源代码阅读之 TreeMap
概要
- 类继承关系
java.lang.Object java.util.AbstractMap<K,V> java.util.HashMap<K,V>
- 定义
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
- 要点
1) 基于 NavigableMap 实现的红黑树 2) 按
Read More ...natrual ordering
或者Comparator
定义的次序排序。 3) 基本操作containsKey
,get
,put
有log(n)
的时间复杂度。 4) 非线程安全 -
- 2014-05-27
开始OpenJDK源代码阅读
在阅读了一周的 OpenJDK 源代码后,我才写这篇文章。因为除非你已经开始阅读,否则是不知道自己是不是应该读下去的。所以,不要贸然说自己要干嘛,先做一段时间,觉得感觉还好,再决定做下去。
这一周,主要是看
Read More ...java.util
中和容器相关的几个文件,虽然还没看太多,但是已经有一些收获了。看到了以前学过的数据结构在Java的标准库中是如何被实现的。也明白了平时使用的一些类的原理是什么。另外,由于最近在看 《Java编程思想》,也能把书中讲的和标准库的源代码对应起来,感觉还不错。还有一个收获就是明白了,基础越扎实,阅读源代码收获也越大,否则根本就看不出一些设计的初衷是什么。之前看到源代码中一些编写程序的方式,我觉得没有必要那样写,后来看《Java编程思想》,才知道为什么会这样写。也有一些是我觉得可以从源代码中学习的东西,从《Java编程思想》中看到,标准库中的编写方式有些是历史遗留问题,不得不那么写,而不是说我们写的时候,也要那样做。这就是说不要迷信那些你不明白的东西,即使他们看起来很权威。 -
- 2014-05-28
OpenJDK 源码阅读之 LinkedList
概要
- 类继承关系
Read More ...java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java.util.AbstractSequentialList<E> java.util.LinkedList<E>