1. package java.util;
  2.  
  3. import java.io.*;
  4. import java.util.concurrent.ThreadLocalRandom;
  5. import java.util.function.BiConsumer;
  6. import java.util.function.Function;
  7. import java.util.function.BiFunction;
  8.  
  9. import sun.misc.SharedSecrets;
  10.  
  11. /**
  12. * Hashtable存储的内容是键值对(key-value)映射,其底层实现是一个Entry数组+链表;
  13. * Hashtable和HashMap一样也是散列表,存储元素也是键值对;
  14. * HashMap允许key和value都为null,而Hashtable都不能为null,Hashtable中的映射不是有序的;
  15. * Hashtable和HashMap扩容的方法不一样,Hashtable中数组默认大小11,扩容方式是 old*2+1。
  16. * HashMap中数组的默认大小是16,而且一定是2的指数,增加为原来的2倍。
  17. * Hashtable继承于Dictionary类(Dictionary类声明了操作键值对的接口方法),实现Map接口(定义键值对接口);
  18. * Hashtable大部分类用synchronized修饰,证明Hashtable是线程安全的。
  19. */
  20. public class Hashtable<K, V>
  21. extends Dictionary<K, V>
  22. implements Map<K, V>, Cloneable, java.io.Serializable {
  23.  
  24. /**
  25. * 键值对/Entry数组,每个Entry本质上是一个单向链表的表头
  26. */
  27. private transient Entry<?, ?>[] table;
  28.  
  29. /**
  30. * 当前表中的Entry数量,如果超过了阈值,就会扩容,即调用rehash方法
  31. */
  32. private transient int count;
  33.  
  34. /**
  35. * rehash阈值
  36. *
  37. * @serial
  38. */
  39. private int threshold;
  40.  
  41. /**
  42. * 负载因子
  43. *
  44. * @serial
  45. */
  46. private float loadFactor;
  47.  
  48. /**
  49. * 用来实现"fail-fast"机制的(也就是快速失败)。所谓快速失败就是在并发集合中,其进行
  50. * 迭代操作时,若有其他线程对其进行结构性的修改,这时迭代器会立马感知到,并且立即抛出
  51. * ConcurrentModificationException异常,而不是等到迭代完成之后才告诉你(你已经出错了)。
  52. */
  53. private transient int modCount = 0;
  54.  
  55. /**
  56. * 版本序列号
  57. */
  58. private static final long serialVersionUID = 1421746759512286392L;
  59.  
  60. /**
  61. * 指定容量大小和加载因子的构造函数
  62. *
  63. * @param initialCapacity 容量大小
  64. * @param loadFactor 负载因子
  65. * @throws IllegalArgumentException if the initial capacity is less
  66. * than zero, or if the load factor is nonpositive.
  67. */
  68. public Hashtable(int initialCapacity, float loadFactor) {
  69. if (initialCapacity < 0)
  70. throw new IllegalArgumentException("Illegal Capacity: " +
  71. initialCapacity);
  72. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  73. throw new IllegalArgumentException("Illegal Load: " + loadFactor);
  74.  
  75. if (initialCapacity == 0)
  76. initialCapacity = 1;
  77. this.loadFactor = loadFactor;
  78. table = new Entry<?, ?>[initialCapacity];
  79. threshold = (int) Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
  80. }
  81.  
  82. /**
  83. * 指定容量大小的构造函数
  84. *
  85. * @param initialCapacity 容量大小
  86. * @throws IllegalArgumentException if the initial capacity is less
  87. * than zero.
  88. */
  89. public Hashtable(int initialCapacity) {
  90. this(initialCapacity, 0.75f);
  91. }
  92.  
  93. /**
  94. * 默认构造函数
  95. */
  96. public Hashtable() {
  97. // 默认构造函数,指定的容量大小是11;加载因子是0.75
  98. this(11, 0.75f);
  99. }
  100.  
  101. /**
  102. * 包含子Map的构造函数
  103. *
  104. * @param t the map whose mappings are to be placed in this map.
  105. * @throws NullPointerException if the specified map is null.
  106. * @since 1.2
  107. */
  108. public Hashtable(Map<? extends K, ? extends V> t) {
  109. this(Math.max(2 * t.size(), 11), 0.75f);
  110. putAll(t);
  111. }
  112.  
  113. /**
  114. * 返回容量大小
  115. *
  116. * @return the number of keys in this hashtable.
  117. */
  118. public synchronized int size() {
  119. return count;
  120. }
  121.  
  122. /**
  123. * 判空
  124. *
  125. * @return <code>true</code> if this hashtable maps no keys to values;
  126. * <code>false</code> otherwise.
  127. */
  128. public synchronized boolean isEmpty() {
  129. return count == 0;
  130. }
  131.  
  132. /**
  133. * 返回所有key的枚举对象
  134. *
  135. * @return an enumeration of the keys in this hashtable.
  136. * @see Enumeration
  137. * @see #elements()
  138. * @see #keySet()
  139. * @see Map
  140. */
  141. public synchronized Enumeration<K> keys() {
  142. return this.<K>getEnumeration(KEYS);
  143. }
  144.  
  145. /**
  146. * 返回所有value的枚举对象
  147. *
  148. * @return an enumeration of the values in this hashtable.
  149. * @see java.util.Enumeration
  150. * @see #keys()
  151. * @see #values()
  152. * @see Map
  153. */
  154. public synchronized Enumeration<V> elements() {
  155. return this.<V>getEnumeration(VALUES);
  156. }
  157.  
  158. /**
  159. * 判断是否含有该value的键值对,在Hashtable中hashCode相同的Entry用链表组织,hashCode不同的存储在Entry数组table中;
  160. *
  161. * @param value a value to search for
  162. * @return <code>true</code> if and only if some key maps to the
  163. * <code>value</code> argument in this hashtable as
  164. * determined by the <tt>equals</tt> method;
  165. * <code>false</code> otherwise.
  166. * @throws NullPointerException if the value is <code>null</code>
  167. */
  168. public synchronized boolean contains(Object value) {
  169. if (value == null) {
  170. throw new NullPointerException();
  171. }
  172.  
  173. Entry<?, ?> tab[] = table;
  174. // 查找:遍历所有Entry链表
  175. for (int i = tab.length; i-- > 0; ) {
  176. for (Entry<?, ?> e = tab[i]; e != null; e = e.next) {
  177. if (e.value.equals(value)) {
  178. return true;
  179. }
  180. }
  181. }
  182. return false;
  183. }
  184.  
  185. /**
  186. * 判断是否包含value值对象
  187. *
  188. * @param value value whose presence in this hashtable is to be tested
  189. * @return <tt>true</tt> if this map maps one or more keys to the
  190. * specified value
  191. * @throws NullPointerException if the value is <code>null</code>
  192. * @since 1.2
  193. */
  194. public boolean containsValue(Object value) {
  195. return contains(value);
  196. }
  197.  
  198. /**
  199. * 判断是否包含key键值对象
  200. *
  201. * @param key possible key
  202. * @return <code>true</code> if and only if the specified object
  203. * is a key in this hashtable, as determined by the
  204. * <tt>equals</tt> method; <code>false</code> otherwise.
  205. * @throws NullPointerException if the key is <code>null</code>
  206. * @see #contains(Object)
  207. */
  208. public synchronized boolean containsKey(Object key) {
  209. Entry<?, ?> tab[] = table;
  210. int hash = key.hashCode();
  211. /**
  212. * 计算index, % tab.length防止数组越界
  213. * index表示key对应entry所在链表表头
  214. */
  215. int index = (hash & 0x7FFFFFFF) % tab.length;
  216. for (Entry<?, ?> e = tab[index]; e != null; e = e.next) {
  217. if ((e.hash == hash) && e.key.equals(key)) {
  218. return true;
  219. }
  220. }
  221. return false;
  222. }
  223.  
  224. /**
  225. * 根据指定key查找对应value,查找原理与containsKey相同,查找成功返回value,否则返回null
  226. *
  227. * @param key the key whose associated value is to be returned
  228. * @return the value to which the specified key is mapped, or
  229. * {@code null} if this map contains no mapping for the key
  230. * @throws NullPointerException if the specified key is null
  231. * @see #put(Object, Object)
  232. */
  233. @SuppressWarnings("unchecked")
  234. public synchronized V get(Object key) {
  235. Entry<?, ?> tab[] = table;
  236. int hash = key.hashCode();
  237. int index = (hash & 0x7FFFFFFF) % tab.length;
  238. for (Entry<?, ?> e = tab[index]; e != null; e = e.next) {
  239. if ((e.hash == hash) && e.key.equals(key)) {
  240. return (V) e.value;
  241. }
  242. }
  243. return null;
  244. }
  245.  
  246. /**
  247. * 规定的最大数组容量
  248. */
  249. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  250.  
  251. /**
  252. * 当Hashtable中键值对总数超过阈值(容量*装载因子)后,内部自动调用rehash()增加容量,重新计算每个键值对的hashCode
  253. * int newCapacity = (oldCapacity << 1) + 1计算新容量 = 2 * 旧容量 + 1;并且根据新容量更新阈值
  254. */
  255. @SuppressWarnings("unchecked")
  256. protected void rehash() {
  257. int oldCapacity = table.length;
  258. Entry<?, ?>[] oldMap = table;
  259.  
  260. /**
  261. * 新的大小为 原大小 * 2 + 1
  262. * 虽然不保证capacity是一个质数,但至少保证它是一个奇数
  263. */
  264. int newCapacity = (oldCapacity << 1) + 1;
  265. if (newCapacity - MAX_ARRAY_SIZE > 0) {
  266. if (oldCapacity == MAX_ARRAY_SIZE)
  267. // Keep running with MAX_ARRAY_SIZE buckets
  268. return;
  269. newCapacity = MAX_ARRAY_SIZE;
  270. }
  271. Entry<?, ?>[] newMap = new Entry<?, ?>[newCapacity];
  272.  
  273. modCount++;
  274. threshold = (int) Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
  275. table = newMap;
  276. // 拷贝每个Entry链表
  277. for (int i = oldCapacity; i-- > 0; ) {
  278. for (Entry<K, V> old = (Entry<K, V>) oldMap[i]; old != null; ) {
  279. Entry<K, V> e = old;
  280. old = old.next;
  281. // 重新计算每个Entry链表的表头索引(rehash)
  282. int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  283. // 开辟链表节点
  284. e.next = (Entry<K, V>) newMap[index];
  285. // 拷贝
  286. newMap[index] = e;
  287. }
  288. }
  289. }
  290.  
  291. /**
  292. * 当键值对个数超过阈值,先进行rehash然后添加entry,否则直接添加entry
  293. */
  294. private void addEntry(int hash, K key, V value, int index) {
  295. modCount++;
  296.  
  297. Entry<?, ?> tab[] = table;
  298. // 当前元素大于等于阈值,就扩容并且再计算hash值
  299. if (count >= threshold) {
  300. rehash();
  301.  
  302. tab = table;
  303. hash = key.hashCode();
  304. index = (hash & 0x7FFFFFFF) % tab.length;
  305. }
  306.  
  307. // Creates the new entry.
  308. @SuppressWarnings("unchecked")
  309. Entry<K, V> e = (Entry<K, V>) tab[index];
  310. // 和HashMap不同,Hashtable选择把新插入的元素放到链表最前边,而且没有使用红黑树
  311. tab[index] = new Entry<>(hash, key, value, e);
  312. count++;
  313. }
  314.  
  315. /**
  316. * 设置键值对,key和value都不可为null,设置顺序:
  317. * 如果Hashtable含有key,设置(key, oldValue) -> (key, newValue);
  318. * 如果Hashtable不含有key, 调用addEntry(...)添加新的键值对;
  319. *
  320. * @param key the hashtable key
  321. * @param value the value
  322. * @return the previous value of the specified key in this hashtable,
  323. * or <code>null</code> if it did not have one
  324. * @throws NullPointerException if the key or value is
  325. * <code>null</code>
  326. * @see Object#equals(Object)
  327. * @see #get(Object)
  328. */
  329. public synchronized V put(K key, V value) {
  330. // value为空抛出空指针异常
  331. if (value == null) {
  332. throw new NullPointerException();
  333. }
  334.  
  335. // Makes sure the key is not already in the hashtable.
  336. Entry<?, ?> tab[] = table;
  337. /**
  338. * key的hashCode是调用Object的hashCode()方法,
  339. * 是native的方法,如果为null,就会抛出空指针异常
  340. */
  341. int hash = key.hashCode();
  342. /**
  343. * 因为hash可能为负数,所以就先和0x7FFFFFFF相与
  344. * 在HashMap中,是用 (table.length - 1) & hash 计算要放置的位置
  345. */
  346. int index = (hash & 0x7FFFFFFF) % tab.length;
  347. @SuppressWarnings("unchecked")
  348. Entry<K, V> entry = (Entry<K, V>) tab[index];
  349. for (; entry != null; entry = entry.next) {
  350. if ((entry.hash == hash) && entry.key.equals(key)) {
  351. V old = entry.value;
  352. entry.value = value;
  353. return old;
  354. }
  355. }
  356. // 如果key对应的值不存在,就调用addEntry方法加入
  357. addEntry(hash, key, value, index);
  358. return null;
  359. }
  360.  
  361. /**
  362. * remove操作,计算key所在链表表头table[index],然后进行单向链表的节点删除操作
  363. *
  364. * @param key the key that needs to be removed
  365. * @return the value to which the key had been mapped in this hashtable,
  366. * or <code>null</code> if the key did not have a mapping
  367. * @throws NullPointerException if the key is <code>null</code>
  368. */
  369. public synchronized V remove(Object key) {
  370. Entry<?, ?> tab[] = table;
  371. int hash = key.hashCode();
  372. int index = (hash & 0x7FFFFFFF) % tab.length;
  373. @SuppressWarnings("unchecked")
  374. Entry<K, V> e = (Entry<K, V>) tab[index];
  375. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  376. if ((e.hash == hash) && e.key.equals(key)) {
  377. modCount++;
  378. if (prev != null) {
  379. prev.next = e.next;
  380. } else {
  381. tab[index] = e.next;
  382. }
  383. count--;
  384. V oldValue = e.value;
  385. e.value = null;
  386. return oldValue;
  387. }
  388. }
  389. return null;
  390. }
  391.  
  392. /**
  393. * 把所有的 映射从指定的map复制到hashTable中
  394. * 如果给定的map中的key值已经存在于hashTable中,则将会覆盖hashTable中key所对应的value(hashTable中key值不允许重复)
  395. *
  396. * @param t mappings to be stored in this map
  397. * @throws NullPointerException if the specified map is null
  398. * @since 1.2
  399. */
  400. public synchronized void putAll(Map<? extends K, ? extends V> t) {
  401. //foreach 循环map数据put到hashTable中
  402. for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
  403. put(e.getKey(), e.getValue());
  404. }
  405.  
  406. /**
  407. * 清空Hashtable
  408. * 将Hashtable的table数组的值全部设为null
  409. */
  410. public synchronized void clear() {
  411. Entry<?, ?> tab[] = table;
  412. modCount++;
  413. for (int index = tab.length; --index >= 0; )
  414. tab[index] = null;
  415. count = 0;
  416. }
  417.  
  418. /**
  419. * 对Hashtable的浅拷贝操作,浅拷贝所有bucket(单向链表组织形式)的表头
  420. *
  421. * @return a clone of the hashtable
  422. */
  423. public synchronized Object clone() {
  424. try {
  425. Hashtable<?, ?> t = (Hashtable<?, ?>) super.clone();
  426. t.table = new Entry<?, ?>[table.length];
  427. for (int i = table.length; i-- > 0; ) {
  428. t.table[i] = (table[i] != null)
  429. ? (Entry<?, ?>) table[i].clone() : null;
  430. }
  431. t.keySet = null;
  432. t.entrySet = null;
  433. t.values = null;
  434. t.modCount = 0;
  435. return t;
  436. } catch (CloneNotSupportedException e) {
  437. // this shouldn't happen, since we are Cloneable
  438. throw new InternalError(e);
  439. }
  440. }
  441.  
  442. /**
  443. * 返回Hashtable对象的String表达方式,一系列以括号和逗号,空格分隔的Entry,如{key1=value1, key2=value2}
  444. *
  445. * @return a string representation of this hashtable
  446. */
  447. public synchronized String toString() {
  448. int max = size() - 1;
  449. if (max == -1)
  450. return "{}";
  451.  
  452. StringBuilder sb = new StringBuilder();
  453. Iterator<Map.Entry<K, V>> it = entrySet().iterator();
  454.  
  455. sb.append('{');
  456. for (int i = 0; ; i++) {
  457. Map.Entry<K, V> e = it.next();
  458. K key = e.getKey();
  459. V value = e.getValue();
  460. sb.append(key == this ? "(this Map)" : key.toString());
  461. sb.append('=');
  462. sb.append(value == this ? "(this Map)" : value.toString());
  463.  
  464. if (i == max)
  465. return sb.append('}').toString();
  466. sb.append(", ");
  467. }
  468. }
  469.  
  470. private <T> Enumeration<T> getEnumeration(int type) {
  471. if (count == 0) {
  472. return Collections.emptyEnumeration();
  473. } else {
  474. return new Enumerator<>(type, false);
  475. }
  476. }
  477.  
  478. /**
  479. * 获得迭代器
  480. */
  481. private <T> Iterator<T> getIterator(int type) {
  482. if (count == 0) {
  483. return Collections.emptyIterator();
  484. } else {
  485. return new Enumerator<>(type, true);
  486. }
  487. }
  488.  
  489. // 视图
  490.  
  491. /**
  492. * 以下每个字段初始化后会包含一个首次请求后的指定视图,视图是无状态的,所以不必创建多个
  493. */
  494. private transient volatile Set<K> keySet;
  495. private transient volatile Set<Map.Entry<K, V>> entrySet;
  496. private transient volatile Collection<V> values;
  497.  
  498. /**
  499. * 返回一个被synchronizedSet封装后的KeySet对象
  500. * synchronizedSet封装的目的是对KeySet的所有方法都添加synchronized,实现多线程同步
  501. */
  502. public Set<K> keySet() {
  503. if (keySet == null)
  504. keySet = Collections.synchronizedSet(new KeySet(), this);
  505. return keySet;
  506. }
  507.  
  508. /**
  509. * Hashtable的Key的Set集合
  510. * KeySet继承于AbstractSet,所以,KeySet中的元素没有重复的
  511. */
  512. private class KeySet extends AbstractSet<K> {
  513. public Iterator<K> iterator() {
  514. return getIterator(KEYS);
  515. }
  516.  
  517. public int size() {
  518. return count;
  519. }
  520.  
  521. public boolean contains(Object o) {
  522. return containsKey(o);
  523. }
  524.  
  525. public boolean remove(Object o) {
  526. return Hashtable.this.remove(o) != null;
  527. }
  528.  
  529. public void clear() {
  530. Hashtable.this.clear();
  531. }
  532. }
  533.  
  534. /**
  535. * 返回一个被synchronizedSet封装后的EntrySet对象
  536. * synchronizedSet封装的目的是对EntrySet的所有方法都添加synchronized,实现多线程同步
  537. */
  538. public Set<Map.Entry<K, V>> entrySet() {
  539. if (entrySet == null)
  540. entrySet = Collections.synchronizedSet(new EntrySet(), this);
  541. return entrySet;
  542. }
  543.  
  544. /**
  545. * Hashtable的Entry的Set集合
  546. * EntrySet继承于AbstractSet,所以,EntrySet中的元素没有重复的
  547. */
  548. private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
  549. public Iterator<Map.Entry<K, V>> iterator() {
  550. return getIterator(ENTRIES);
  551. }
  552.  
  553. public boolean add(Map.Entry<K, V> o) {
  554. return super.add(o);
  555. }
  556.  
  557. /**
  558. * 查找EntrySet中是否包含Object(0)
  559. * 首先,在table中找到o对应的Entry(Entry是一个单向链表)
  560. * 然后,查找Entry链表中是否存在Object
  561. */
  562. public boolean contains(Object o) {
  563. if (!(o instanceof Map.Entry))
  564. return false;
  565. Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
  566. Object key = entry.getKey();
  567. Entry<?, ?>[] tab = table;
  568. int hash = key.hashCode();
  569. int index = (hash & 0x7FFFFFFF) % tab.length;
  570.  
  571. for (Entry<?, ?> e = tab[index]; e != null; e = e.next)
  572. if (e.hash == hash && e.equals(entry))
  573. return true;
  574. return false;
  575. }
  576.  
  577. /**
  578. * 删除元素Object(0)
  579. * 首先,在table中找到o对应的Entry(Entry是一个单向链表)
  580. * 然后,删除链表中的元素Object
  581. */
  582. public boolean remove(Object o) {
  583. if (!(o instanceof Map.Entry))
  584. return false;
  585. Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
  586. Object key = entry.getKey();
  587. Entry<?, ?>[] tab = table;
  588. int hash = key.hashCode();
  589. int index = (hash & 0x7FFFFFFF) % tab.length;
  590.  
  591. @SuppressWarnings("unchecked")
  592. Entry<K, V> e = (Entry<K, V>) tab[index];
  593. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  594. if (e.hash == hash && e.equals(entry)) {
  595. modCount++;
  596. if (prev != null)
  597. prev.next = e.next;
  598. else
  599. tab[index] = e.next;
  600.  
  601. count--;
  602. e.value = null;
  603. return true;
  604. }
  605. }
  606. return false;
  607. }
  608.  
  609. public int size() {
  610. return count;
  611. }
  612.  
  613. public void clear() {
  614. Hashtable.this.clear();
  615. }
  616. }
  617.  
  618. /**
  619. * 返回一个被synchronizedCollection封装后的ValueCollection对象
  620. * synchronizedCollection封装的目的是对ValueCollection的所有方法都添加synchronized,实现多线程同步
  621. */
  622. public Collection<V> values() {
  623. if (values == null)
  624. values = Collections.synchronizedCollection(new ValueCollection(),
  625. this);
  626. return values;
  627. }
  628.  
  629. /**
  630. * Hashtable的value的Collection集合。
  631. * ValueCollection继承于AbstractCollection,所以,ValueCollection中的元素可以重复的。
  632. */
  633. private class ValueCollection extends AbstractCollection<V> {
  634. public Iterator<V> iterator() {
  635. return getIterator(VALUES);
  636. }
  637.  
  638. public int size() {
  639. return count;
  640. }
  641.  
  642. public boolean contains(Object o) {
  643. return containsValue(o);
  644. }
  645.  
  646. public void clear() {
  647. Hashtable.this.clear();
  648. }
  649. }
  650.  
  651. // Comparison and hashing
  652.  
  653. /**
  654. * 重新equals()函数
  655. * 若两个Hashtable的所有key-value键值对都相等,则判断它们两个相等
  656. *
  657. * @param o object to be compared for equality with this hashtable
  658. * @return true if the specified Object is equal to this Map
  659. * @see Map#equals(Object)
  660. * @since 1.2
  661. */
  662. public synchronized boolean equals(Object o) {
  663. if (o == this)
  664. return true;
  665.  
  666. if (!(o instanceof Map))
  667. return false;
  668. Map<?, ?> t = (Map<?, ?>) o;
  669. if (t.size() != size())
  670. return false;
  671.  
  672. try {
  673. /**
  674. * 通过迭代器依次取出当前Hashtable的key-value键值对
  675. * 并判断该键值对,存在于Hashtable(o)中。
  676. * 若不存在,则立即返回false;否则,遍历完“当前Hashtable”并返回true。
  677. */
  678. Iterator<Map.Entry<K, V>> i = entrySet().iterator();
  679. while (i.hasNext()) {
  680. Map.Entry<K, V> e = i.next();
  681. K key = e.getKey();
  682. V value = e.getValue();
  683. if (value == null) {
  684. if (!(t.get(key) == null && t.containsKey(key)))
  685. return false;
  686. } else {
  687. if (!value.equals(t.get(key)))
  688. return false;
  689. }
  690. }
  691. } catch (ClassCastException unused) {
  692. return false;
  693. } catch (NullPointerException unused) {
  694. return false;
  695. }
  696.  
  697. return true;
  698. }
  699.  
  700. /**
  701. * 计算Hashtable的哈希值
  702. *
  703. * @see Map#hashCode()
  704. * @since 1.2
  705. */
  706. public synchronized int hashCode() {
  707. int h = 0;
  708. //若 Hashtable的实际大小为0 或者 加载因子<0,则返回0
  709. if (count == 0 || loadFactor < 0)
  710. return h; // Returns zero
  711.  
  712. loadFactor = -loadFactor; // Mark hashCode computation in progress
  713. Entry<?, ?>[] tab = table;
  714. //返回Hashtable中的每个Entry的key和value的异或值的总和
  715. for (Entry<?, ?> entry : tab) {
  716. while (entry != null) {
  717. h += entry.hashCode();
  718. entry = entry.next;
  719. }
  720. }
  721.  
  722. loadFactor = -loadFactor; // Mark hashCode computation complete
  723.  
  724. return h;
  725. }
  726.  
  727. @Override
  728. public synchronized V getOrDefault(Object key, V defaultValue) {
  729. V result = get(key);
  730. return (null == result) ? defaultValue : result;
  731. }
  732.  
  733. @SuppressWarnings("unchecked")
  734. @Override
  735. public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
  736. Objects.requireNonNull(action); // explicit check required in case
  737. // table is empty.
  738. final int expectedModCount = modCount;
  739.  
  740. Entry<?, ?>[] tab = table;
  741. for (Entry<?, ?> entry : tab) {
  742. while (entry != null) {
  743. action.accept((K) entry.key, (V) entry.value);
  744. entry = entry.next;
  745.  
  746. if (expectedModCount != modCount) {
  747. throw new ConcurrentModificationException();
  748. }
  749. }
  750. }
  751. }
  752.  
  753. @SuppressWarnings("unchecked")
  754. @Override
  755. public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
  756. Objects.requireNonNull(function); // explicit check required in case
  757. // table is empty.
  758. final int expectedModCount = modCount;
  759.  
  760. Entry<K, V>[] tab = (Entry<K, V>[]) table;
  761. for (Entry<K, V> entry : tab) {
  762. while (entry != null) {
  763. entry.value = Objects.requireNonNull(
  764. function.apply(entry.key, entry.value));
  765. entry = entry.next;
  766.  
  767. if (expectedModCount != modCount) {
  768. throw new ConcurrentModificationException();
  769. }
  770. }
  771. }
  772. }
  773.  
  774. @Override
  775. public synchronized V putIfAbsent(K key, V value) {
  776. Objects.requireNonNull(value);
  777.  
  778. // Makes sure the key is not already in the hashtable.
  779. Entry<?, ?> tab[] = table;
  780. int hash = key.hashCode();
  781. int index = (hash & 0x7FFFFFFF) % tab.length;
  782. @SuppressWarnings("unchecked")
  783. Entry<K, V> entry = (Entry<K, V>) tab[index];
  784. for (; entry != null; entry = entry.next) {
  785. if ((entry.hash == hash) && entry.key.equals(key)) {
  786. V old = entry.value;
  787. if (old == null) {
  788. entry.value = value;
  789. }
  790. return old;
  791. }
  792. }
  793.  
  794. addEntry(hash, key, value, index);
  795. return null;
  796. }
  797.  
  798. @Override
  799. public synchronized boolean remove(Object key, Object value) {
  800. Objects.requireNonNull(value);
  801.  
  802. Entry<?, ?> tab[] = table;
  803. int hash = key.hashCode();
  804. int index = (hash & 0x7FFFFFFF) % tab.length;
  805. @SuppressWarnings("unchecked")
  806. Entry<K, V> e = (Entry<K, V>) tab[index];
  807. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  808. if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
  809. modCount++;
  810. if (prev != null) {
  811. prev.next = e.next;
  812. } else {
  813. tab[index] = e.next;
  814. }
  815. count--;
  816. e.value = null;
  817. return true;
  818. }
  819. }
  820. return false;
  821. }
  822.  
  823. @Override
  824. public synchronized boolean replace(K key, V oldValue, V newValue) {
  825. Objects.requireNonNull(oldValue);
  826. Objects.requireNonNull(newValue);
  827. Entry<?, ?> tab[] = table;
  828. int hash = key.hashCode();
  829. int index = (hash & 0x7FFFFFFF) % tab.length;
  830. @SuppressWarnings("unchecked")
  831. Entry<K, V> e = (Entry<K, V>) tab[index];
  832. for (; e != null; e = e.next) {
  833. if ((e.hash == hash) && e.key.equals(key)) {
  834. if (e.value.equals(oldValue)) {
  835. e.value = newValue;
  836. return true;
  837. } else {
  838. return false;
  839. }
  840. }
  841. }
  842. return false;
  843. }
  844.  
  845. /**
  846. * 替换
  847. *
  848. * @param key
  849. * @param value
  850. * @return
  851. */
  852. @Override
  853. public synchronized V replace(K key, V value) {
  854. Objects.requireNonNull(value);
  855. Entry<?, ?> tab[] = table;
  856. int hash = key.hashCode();
  857. int index = (hash & 0x7FFFFFFF) % tab.length;
  858. @SuppressWarnings("unchecked")
  859. Entry<K, V> e = (Entry<K, V>) tab[index];
  860. for (; e != null; e = e.next) {
  861. if ((e.hash == hash) && e.key.equals(key)) {
  862. V oldValue = e.value;
  863. e.value = value;
  864. return oldValue;
  865. }
  866. }
  867. return null;
  868. }
  869.  
  870. @Override
  871. public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
  872. Objects.requireNonNull(mappingFunction);
  873.  
  874. Entry<?, ?> tab[] = table;
  875. int hash = key.hashCode();
  876. int index = (hash & 0x7FFFFFFF) % tab.length;
  877. @SuppressWarnings("unchecked")
  878. Entry<K, V> e = (Entry<K, V>) tab[index];
  879. for (; e != null; e = e.next) {
  880. if (e.hash == hash && e.key.equals(key)) {
  881. // Hashtable not accept null value
  882. return e.value;
  883. }
  884. }
  885.  
  886. V newValue = mappingFunction.apply(key);
  887. if (newValue != null) {
  888. addEntry(hash, key, newValue, index);
  889. }
  890.  
  891. return newValue;
  892. }
  893.  
  894. @Override
  895. public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
  896. Objects.requireNonNull(remappingFunction);
  897.  
  898. Entry<?, ?> tab[] = table;
  899. int hash = key.hashCode();
  900. int index = (hash & 0x7FFFFFFF) % tab.length;
  901. @SuppressWarnings("unchecked")
  902. Entry<K, V> e = (Entry<K, V>) tab[index];
  903. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  904. if (e.hash == hash && e.key.equals(key)) {
  905. V newValue = remappingFunction.apply(key, e.value);
  906. if (newValue == null) {
  907. modCount++;
  908. if (prev != null) {
  909. prev.next = e.next;
  910. } else {
  911. tab[index] = e.next;
  912. }
  913. count--;
  914. } else {
  915. e.value = newValue;
  916. }
  917. return newValue;
  918. }
  919. }
  920. return null;
  921. }
  922.  
  923. @Override
  924. public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
  925. Objects.requireNonNull(remappingFunction);
  926.  
  927. Entry<?, ?> tab[] = table;
  928. int hash = key.hashCode();
  929. int index = (hash & 0x7FFFFFFF) % tab.length;
  930. @SuppressWarnings("unchecked")
  931. Entry<K, V> e = (Entry<K, V>) tab[index];
  932. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  933. if (e.hash == hash && Objects.equals(e.key, key)) {
  934. V newValue = remappingFunction.apply(key, e.value);
  935. if (newValue == null) {
  936. modCount++;
  937. if (prev != null) {
  938. prev.next = e.next;
  939. } else {
  940. tab[index] = e.next;
  941. }
  942. count--;
  943. } else {
  944. e.value = newValue;
  945. }
  946. return newValue;
  947. }
  948. }
  949.  
  950. V newValue = remappingFunction.apply(key, null);
  951. if (newValue != null) {
  952. addEntry(hash, key, newValue, index);
  953. }
  954.  
  955. return newValue;
  956. }
  957.  
  958. @Override
  959. public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
  960. Objects.requireNonNull(remappingFunction);
  961.  
  962. Entry<?, ?> tab[] = table;
  963. int hash = key.hashCode();
  964. int index = (hash & 0x7FFFFFFF) % tab.length;
  965. @SuppressWarnings("unchecked")
  966. Entry<K, V> e = (Entry<K, V>) tab[index];
  967. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  968. if (e.hash == hash && e.key.equals(key)) {
  969. V newValue = remappingFunction.apply(e.value, value);
  970. if (newValue == null) {
  971. modCount++;
  972. if (prev != null) {
  973. prev.next = e.next;
  974. } else {
  975. tab[index] = e.next;
  976. }
  977. count--;
  978. } else {
  979. e.value = newValue;
  980. }
  981. return newValue;
  982. }
  983. }
  984.  
  985. if (value != null) {
  986. addEntry(hash, key, value, index);
  987. }
  988.  
  989. return value;
  990. }
  991.  
  992. /**
  993. * 将Hashtable的总的容量,实际容量,所有的Entry都写入到输出流中
  994. */
  995. private void writeObject(java.io.ObjectOutputStream s)
  996. throws IOException {
  997. Entry<Object, Object> entryStack = null;
  998.  
  999. synchronized (this) {
  1000. // Write out the threshold and loadFactor
  1001. s.defaultWriteObject();
  1002.  
  1003. // Write out the length and count of elements
  1004. s.writeInt(table.length);
  1005. s.writeInt(count);
  1006.  
  1007. // Stack copies of the entries in the table
  1008. for (int index = 0; index < table.length; index++) {
  1009. Entry<?, ?> entry = table[index];
  1010.  
  1011. while (entry != null) {
  1012. entryStack =
  1013. new Entry<>(0, entry.key, entry.value, entryStack);
  1014. entry = entry.next;
  1015. }
  1016. }
  1017. }
  1018.  
  1019. // Write out the key/value objects from the stacked entries
  1020. while (entryStack != null) {
  1021. s.writeObject(entryStack.key);
  1022. s.writeObject(entryStack.value);
  1023. entryStack = entryStack.next;
  1024. }
  1025. }
  1026.  
  1027. /**
  1028. * 将Hashtable的总的容量,实际容量,所有的Entry依次读出
  1029. */
  1030. private void readObject(java.io.ObjectInputStream s)
  1031. throws IOException, ClassNotFoundException {
  1032. // Read in the threshold and loadFactor
  1033. s.defaultReadObject();
  1034.  
  1035. // Validate loadFactor (ignore threshold - it will be re-computed)
  1036. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  1037. throw new StreamCorruptedException("Illegal Load: " + loadFactor);
  1038.  
  1039. // Read the original length of the array and number of elements
  1040. int origlength = s.readInt();
  1041. int elements = s.readInt();
  1042.  
  1043. // Validate # of elements
  1044. if (elements < 0)
  1045. throw new StreamCorruptedException("Illegal # of Elements: " + elements);
  1046.  
  1047. // Clamp original length to be more than elements / loadFactor
  1048. // (this is the invariant enforced with auto-growth)
  1049. origlength = Math.max(origlength, (int) (elements / loadFactor) + 1);
  1050.  
  1051. // Compute new length with a bit of room 5% + 3 to grow but
  1052. // no larger than the clamped original length. Make the length
  1053. // odd if it's large enough, this helps distribute the entries.
  1054. // Guard against the length ending up zero, that's not valid.
  1055. int length = (int) ((elements + elements / 20) / loadFactor) + 3;
  1056. if (length > elements && (length & 1) == 0)
  1057. length--;
  1058. length = Math.min(length, origlength);
  1059.  
  1060. // Check Map.Entry[].class since it's the nearest public type to
  1061. // what we're actually creating.
  1062. SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
  1063. table = new Entry<?, ?>[length];
  1064. threshold = (int) Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
  1065. count = 0;
  1066.  
  1067. // Read the number of elements and then all the key/value objects
  1068. for (; elements > 0; elements--) {
  1069. @SuppressWarnings("unchecked")
  1070. K key = (K) s.readObject();
  1071. @SuppressWarnings("unchecked")
  1072. V value = (V) s.readObject();
  1073. // sync is eliminated for performance
  1074. reconstitutionPut(table, key, value);
  1075. }
  1076. }
  1077.  
  1078. /**
  1079. * readObject使用的put方法(重建put),因为put方法支持重写,并且子类尚未初始化的时候不能调用put方法,所以就提供了reconstitutionPut
  1080. * 它和常规put方法有几点不同,不检测rehash,因为初始元素数目已知。modCount不会自增,因为我们是在创建一个新的实例。
  1081. */
  1082. private void reconstitutionPut(Entry<?, ?>[] tab, K key, V value)
  1083. throws StreamCorruptedException {
  1084. if (value == null) {
  1085. throw new java.io.StreamCorruptedException();
  1086. }
  1087. // 确保Key不在Hashtable中
  1088. // 反序列化过程中不应该 会发生的情况
  1089. int hash = key.hashCode();
  1090. int index = (hash & 0x7FFFFFFF) % tab.length;
  1091. for (Entry<?, ?> e = tab[index]; e != null; e = e.next) {
  1092. //反序列化过程中如果出现Key值重复,抛出异常StreamCorruptedException
  1093. if ((e.hash == hash) && e.key.equals(key)) {
  1094. throw new java.io.StreamCorruptedException();
  1095. }
  1096. }
  1097. // 创建新的Entry.
  1098. @SuppressWarnings("unchecked")
  1099. Entry<K, V> e = (Entry<K, V>) tab[index];
  1100. tab[index] = new Entry<>(hash, key, value, e);
  1101. count++;
  1102. }
  1103.  
  1104. /**
  1105. * Hashtable的Entry节点,它本质上是一个单向链表。
  1106. * 因此,我们能推断出Hashtable是由拉链法实现的散列表
  1107. */
  1108. private static class Entry<K, V> implements Map.Entry<K, V> {
  1109. final int hash;
  1110. final K key;
  1111. V value;
  1112. Entry<K, V> next;
  1113.  
  1114. protected Entry(int hash, K key, V value, Entry<K, V> next) {
  1115. this.hash = hash;
  1116. this.key = key;
  1117. this.value = value;
  1118. this.next = next;
  1119. }
  1120.  
  1121. @SuppressWarnings("unchecked")
  1122. protected Object clone() {
  1123. return new Entry<>(hash, key, value,
  1124. (next == null ? null : (Entry<K, V>) next.clone()));
  1125. }
  1126.  
  1127. // Map.Entry Ops
  1128.  
  1129. public K getKey() {
  1130. return key;
  1131. }
  1132.  
  1133. public V getValue() {
  1134. return value;
  1135. }
  1136.  
  1137. // 进行判断value是否为空,即不允许value为空,其实key也不能为空
  1138. public V setValue(V value) {
  1139. if (value == null)
  1140. throw new NullPointerException();
  1141.  
  1142. V oldValue = this.value;
  1143. this.value = value;
  1144. return oldValue;
  1145. }
  1146.  
  1147. // 覆盖equals()方法,判断两个Entry是否相等。
  1148. // 若两个Entry的key和value都相等,则认为它们相等。
  1149. public boolean equals(Object o) {
  1150. if (!(o instanceof Map.Entry))
  1151. return false;
  1152. Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
  1153.  
  1154. return (key == null ? e.getKey() == null : key.equals(e.getKey())) &&
  1155. (value == null ? e.getValue() == null : value.equals(e.getValue()));
  1156. }
  1157.  
  1158. public int hashCode() {
  1159. // 直接用hash进行异或,与HashMap不同
  1160. return hash ^ Objects.hashCode(value);
  1161. }
  1162.  
  1163. public String toString() {
  1164. return key.toString() + "=" + value.toString();
  1165. }
  1166. }
  1167.  
  1168. // Types of Enumerations/Iterations
  1169. private static final int KEYS = 0;
  1170. private static final int VALUES = 1;
  1171. private static final int ENTRIES = 2;
  1172.  
  1173. /**
  1174. * Enumerator的作用是提供了通过elements()遍历Hashtable的接口和通过entrySet()遍历Hashtable的接口。
  1175. * 因为,它同时实现了 Enumerator接口和Iterator接口。
  1176. */
  1177. private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
  1178. // 指向Hashtable的table
  1179. Entry<?, ?>[] table = Hashtable.this.table;
  1180. // Hashtable的总的大小
  1181. int index = table.length;
  1182. Entry<?, ?> entry;
  1183. Entry<?, ?> lastReturned;
  1184. int type;
  1185.  
  1186. /**
  1187. * Enumerator是 迭代器(Iterator) 还是 枚举类(Enumeration)的标志
  1188. * iterator为true,表示它是迭代器;否则,是枚举类。
  1189. */
  1190. boolean iterator;
  1191.  
  1192. /**
  1193. * 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
  1194. */
  1195. protected int expectedModCount = modCount;
  1196.  
  1197. Enumerator(int type, boolean iterator) {
  1198. this.type = type;
  1199. this.iterator = iterator;
  1200. }
  1201.  
  1202. /**
  1203. * 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
  1204. */
  1205. public boolean hasMoreElements() {
  1206. Entry<?, ?> e = entry;
  1207. int i = index;
  1208. Entry<?, ?>[] t = table;
  1209. /* Use locals for faster loop iteration */
  1210. while (e == null && i > 0) {
  1211. e = t[--i];
  1212. }
  1213. entry = e;
  1214. index = i;
  1215. return e != null;
  1216. }
  1217.  
  1218. /**
  1219. * 获取下一个元素
  1220. * 注意:从hasMoreElements() 和nextElement() 可以看出Hashtable的elements()遍历方式
  1221. * 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
  1222. * 然后,依次向后遍历单向链表Entry。
  1223. */
  1224. @SuppressWarnings("unchecked")
  1225. public T nextElement() {
  1226. Entry<?, ?> et = entry;
  1227. int i = index;
  1228. Entry<?, ?>[] t = table;
  1229. /* Use locals for faster loop iteration */
  1230. while (et == null && i > 0) {
  1231. et = t[--i];
  1232. }
  1233. entry = et;
  1234. index = i;
  1235. if (et != null) {
  1236. Entry<?, ?> e = lastReturned = entry;
  1237. entry = e.next;
  1238. return type == KEYS ? (T) e.key : (type == VALUES ? (T) e.value : (T) e);
  1239. }
  1240. throw new NoSuchElementException("Hashtable Enumerator");
  1241. }
  1242.  
  1243. // 迭代器Iterator的判断是否存在下一个元素
  1244. // 实际上,它是调用的hasMoreElements()
  1245. public boolean hasNext() {
  1246. return hasMoreElements();
  1247. }
  1248.  
  1249. // 迭代器获取下一个元素
  1250. // 实际上,它是调用的nextElement()
  1251. public T next() {
  1252. if (modCount != expectedModCount)
  1253. throw new ConcurrentModificationException();
  1254. return nextElement();
  1255. }
  1256.  
  1257. // 迭代器的remove()接口。
  1258. // 首先,它在table数组中找出要删除元素所在的Entry,
  1259. // 然后,删除单向链表Entry中的元素。
  1260. public void remove() {
  1261. if (!iterator)
  1262. throw new UnsupportedOperationException();
  1263. if (lastReturned == null)
  1264. throw new IllegalStateException("Hashtable Enumerator");
  1265. if (modCount != expectedModCount)
  1266. throw new ConcurrentModificationException();
  1267.  
  1268. synchronized (Hashtable.this) {
  1269. Entry<?, ?>[] tab = Hashtable.this.table;
  1270. int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
  1271.  
  1272. //获取该槽位第一个元素
  1273. @SuppressWarnings("unchecked")
  1274. Entry<K, V> e = (Entry<K, V>) tab[index];
  1275. //从单链表的一端向后遍历
  1276. for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
  1277. //当前元素即为上一个返回元素
  1278. if (e == lastReturned) {
  1279. modCount++;
  1280. expectedModCount++;
  1281. //删除上一个元素
  1282. if (prev == null)
  1283. tab[index] = e.next;
  1284. else
  1285. prev.next = e.next;
  1286. count--;
  1287. lastReturned = null;
  1288. return;
  1289. }
  1290. }
  1291. throw new ConcurrentModificationException();
  1292. }
  1293. }
  1294. }
  1295. }

Hashtable源码解析(JDK1.8)的更多相关文章

  1. 源码解析JDK1.8-HashMap链表成环的问题解决方案

    前言 上篇文章详解介绍了HashMap在JDK1.7版本中链表成环的原因,今天介绍下JDK1.8针对HashMap线程安全问题的解决方案. jdk1.8 扩容源码解析 public class Has ...

  2. Java集合-ArrayList源码解析-JDK1.8

    ◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...

  3. ArrayList、CopyOnWriteArrayList源码解析(JDK1.8)

    本篇文章主要是学习后的知识记录,存在不足,或许不够深入,还请谅解. 目录 ArrayList源码解析 ArrayList中的变量 ArrayList构造函数 ArrayList中的add方法 Arra ...

  4. Hashtable源码解析

    Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. Hashtable也是JDK1.0引入的 ...

  5. Map集合类(一.hashMap源码解析jdk1.8)

    java集合笔记一 java集合笔记二 java集合笔记三 jdk 8 之前,其内部是由数组+链表来实现的,而 jdk 8 对于链表长度超过 8 的链表将转储为红黑树 1.属性 //节点数组,第一次使 ...

  6. Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  7. 【转】Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  8. Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析

    目录 为什么要使用ConcurrentHashMap? ConcurrentHashMap的结构特点 Java8之前 Java8之后 基本常量 重要成员变量 构造方法 tableSizeFor put ...

  9. [源码解析]HashMap和HashTable的区别(源码分析解读)

    前言: 又是一个大好的周末, 可惜今天起来有点晚, 扒开HashMap和HashTable, 看看他们到底有什么区别吧. 先来一段比较拗口的定义: Hashtable 的实例有两个参数影响其性能:初始 ...

随机推荐

  1. SpringCloud入门1-服务注册与发现(Eureka)

    前言 Oracle转让Java,各种动态语言的曝光率上升,Java工程师的未来在哪里?我觉得Spring Cloud让未来有无限可能.拖了半年之久的Spring Cloud学习就从今天开始了.中文教材 ...

  2. 最短路径问题(Floyd-Warshall模板)

    #include<bits/stdc++.h> using namespace std; int n; int x,y; ][]; ][]; int m,s,t; int main() { ...

  3. Shell 脚本实践

    1. 脚本判断命令输出是否为空 (1)判断字符串为空 if [ "$str" =  "" ]  if [ x"$str" = x ] if ...

  4. hive:排序分析函数

    基本排序函数 语法: rank()over([partition by col1] order by col2) dense_rank()over([partition by col1] order ...

  5. iOS 开发之内存泄漏问题

    关于内存泄漏问题,一般情况下就是控制器或者视图没有正常的释放引起的,我们通常可以通过dealloc方法来检查一个控制器或者视图是否释放. 对于一个控制器或者视图没有释放,其实也就是还有强引用引用着这个 ...

  6. 用Node.JS+MongoDB搭建个人博客(万众期待的router.js)(四)

    万众期待的router.js,是我现在最想写的一个博客.因为他包含了整个个人博客的精髓.在这里,所有的请求配置,返回的参数等等所做的业务逻辑都在这个文件里实现. 我会详细说明这些代码的作用,所以这篇博 ...

  7. 分布式mysql中间件(mycat)

    1.   MyCAT概述 1.1 背景 随着传统的数据库技术日趋成熟.计算机网络技术的飞速发展和应用范围的扩充,数据库应用已经普遍建立于计算机网络之上.这时集中式数据库系统表现出它的不足: (1)集中 ...

  8. GOF 23种设计模式

    设计模式目录 创建型 1. Factory Method(工厂方法) 2. Abstract Factory(抽象工厂) 3. Builder(建造者) 4. Prototype(原型) 5. Sin ...

  9. CSS3之Border-radius

    1.属性介绍 border-radius:none|12.3px,取值不可为负数,表示边框圆角 相关属性:border-top-right-radius , border-bottom-right-r ...

  10. freemarker报错之十

    1.错误描述 <html> <head> <meta http-equiv="content-type" content="text/htm ...