JAVA架构师之路

本系列文章均是博主原创,意在记录学习上的知识,同时一起分享学习心得。
第一章
第一节 Java集合总结(架构师之路 )
第二节 Java多线程(架构师之路 )


前言
本章内容是博主学习路程的一些重点笔记,主要是为了方便自己以后的回看,同时也跟大家一起分享心得。
若您有发现不对的地方,请私信博主进行更正,谢谢。

目录

  • JAVA架构师之路
    • 1. Java集合概述
    • 2、Collection
      • 2.1 Set
        • 2.1.1 HashSet
        • 2.1.2 LinkedHashSet
        • 2.1.3 TreeSet
      • 2.2 List
        • 2.2.1 ArrayList
        • 2.2.2 LinkedList
        • 2.2.1 Vector
      • 2.3 Queue
        • 2.2.1 BlokingQueue
          • 2.2.1.1 ArrayBlockingQueue
          • 2.2.1.2 LinkedBlockingQueue
        • 2.2.2 Deque
          • 2.2.2.1 LinkedBlockingDeque
    • 3、Map
      • 3.1 Hashtable
      • 3.2 HashMap
        • 3.2.1 LinkedHashMap
      • 3.3 TreeMap
      • 3.4 拓展知识

1. Java集合概述

集合框架:用于存储数据的容器。
1)集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
2)任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

集合的顶级父类为Collection、Map,下图为各自的实现类:

2、Collection

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。

2.1 Set

Set继承了Collection接口,它本身也是一个接口,留给子类实现。

2.1.1 HashSet

  • HashSet实现了Set接口,其特点是元素无序、不可重复。
  • 其内部是使用一个HashMap作为实际存储容器,所以其特性也跟HashMap相似。

其add()方法的执行过程如下:

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();public boolean add(E e) {return map.put(e, PRESENT)==null;
}

可以看出HashSet的add方法其实是使用了HashMap,将其存储的元素值,作为HashMap的key,用一个空的Object作为值。从而达到其元素无序、不可重复的特性。

使用实例代码:

public static void main(String[] args) {Set s = new HashSet();s.add("1");s.add("1");s.add("2");System.out.println(s.size());
}

2.1.2 LinkedHashSet

  • LinkedHashSet继承了HashSet,其特点是元素有序、不可重复。
  • 以哈希表和链表实现的set集合接口,迭代方式和我们预想的一致(因为查询速度的原因底层使用了散列,但是看起来它使用了链表来维护元素的插入顺序),这和hashset实现方式是不同的,因为在它所有的插入过程中都保持了一个双向链表的属性。
  • 链表定义了迭代顺序,即为我们向集合set中插入元素的顺序。注意如果一个元素被重复插入到集合中并不会改变集合的插入顺序。(如果元素e被添加到集合s中,会调用s.add(e)方法,但是s.contains(e)会在s.add(e)方法之前调用并返回true)。

示例代码:

public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet();set.add("1");set.add("2");set.add("3");set.add("1");for (String s:set) {System.out.println(s);}
}

2.1.3 TreeSet

  • TreeSet 类继承了 AbstractSet抽象类和实现了NavigableSet接口,间接也实现 SortedSet 接口,元素不能重复;
  • 由于 SortedSet 接口能对元素升序排序(也叫自然排序),TreeSet 类也会对实现了 Comparable 接口
    的类的对象自动排序,或者根据创建 TreeSet 时提供的 Comparator 进行排序;
  • 底层依赖于 NavigableMap,元素没有索引;
  • 通过红黑树实现,不允许放入null值;
  • 存储大量的需要进行快速检索的排序信息时,TreeSet 是一个很好的选择;
public static void treeSet(){TreeSet<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {// 返回值大于0,倒序return o1 - o2;}});treeSet.add(1);treeSet.add(2);treeSet.add(3);Iterator<Integer> in = treeSet.iterator();while (in.hasNext()) {System.out.println(in.next());}
}

2.2 List

List继承了Collection接口,其本身也是一个接口,主要特点是定义一个有序、元素可重复的容器。

2.2.1 ArrayList

ArrayList实现了List接口,其主要特点是有序、元素可重复。

  • 底层为一个Object数组
  • 数组初始化容量为10
  • 扩容方式,先根据目前的容量*1.5倍计算出新容量;然后将新容量跟目前要装载的数据长度再做比较,取较大值;最后判断新容量是否大于int类型的最大值-8,若为大于,再将int最大值跟目前要装载的数据长度比较,若为大于,取int类型的最大值-8,否则取int类型的最大值;
// 扩容方式
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}

代码实例:

public static void arrayList(){List<Integer> list = new ArrayList();list.add(1);list.add(1);list.add(2);list.add(3);for (Integer i : list) {System.out.println(i);}
}

2.2.2 LinkedList

  • LinkedList也实现了List接口,相对于ArrayList来说,它们的最大区别在于底层数据结构不同,LinkedList的底层是一个双向链表,这也决定了它的最大优点,那就是对于数据的修改比ArrayList更加方便快捷。
  • 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,类似于插入数据,删除数据时,LinkedList也优于ArrayList,其时间复杂度仅为O(1),而ArrayList删除数据是开销很大的,因为这需要重排数组中的所有数据(除了最后一个元素)。
  • 底层维护了两个Node节点,分别为first和last。node节点数据结构包含前后node,以及自身的值。
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

实例代码:

public static void linkedList(){LinkedList<Integer> linkedList = new LinkedList();linkedList.add(1);linkedList.add(2);linkedList.add(3);System.out.println(linkedList.get(2));
}

2.2.1 Vector

  • Vector和ArrayList的实现方式是一样的,区别在于Vector在某些方法上加了synchronized同步关键字。
public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}

实例代码:

public static void vector(){Vector<Integer> vector = new Vector();vector.add(1);vector.add(2);vector.add(3);Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {vector.add(13);}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}vector.add(15);}});t2.run();t1.run();for (Integer i : vector) {System.out.println(i);}
}

2.3 Queue

Queue是java中实现队列的接口,他继承Collection接口,总共只有6个方法。
Queue的6个方法分类:
压入元素(添加):add()、offer()
相同:未超出容量,从队尾压入元素,返回压入的那个元素。
区别:在超出容量时,add()方法会对抛出异常,offer()返回false

弹出元素(删除):remove()、poll()
相同:容量大于0的时候,删除并返回队头被删除的那个元素。
区别:在容量为0的时候,remove()会抛出异常,poll()返回false

获取队头元素(不删除):element()、peek()
相同:容量大于0的时候,都返回队头元素。但是不删除。
区别:容量为0的时候,element()会抛出异常,peek()返回null。

2.2.1 BlokingQueue

BlokingQueue是继承了Queue接口,本身也是一个接口。
特点:

  • 阻塞队列
  • 向队列中添加元素时,队列的长度已满阻塞当前添加线程,直到队列未满或者等待超时;
  • 从队列中获取元素时,队列中元素为空 ,会将获取元素的线程阻塞,直到队列中存在元素 或者等待超时。

方法简解

  1. puts操作
    add(E e) : 添加成功返回true,失败抛IllegalStateException异常
    offer(E e) : 成功返回 true,如果此队列已满,则返回 false(如果添加了时间参数,且队列已满也会阻塞)
    put(E e) :将元素插入此队列的尾部,如果该队列已满,则一直阻塞
  2. takes操作
    remove(Object o) :移除指定元素,成功返回true,失败返回false
    poll() : 获取并移除此队列的头元素,若队列为空,则返回 null(如果添加了时间参数,且队列中没有数据也会阻塞)
    take():获取并移除此队列头元素,若没有元素则一直阻塞。
    peek() :获取但不移除此队列的头;若队列为空,则返回 null。
  3. other操作
    contains(Object o):队列中是否包含指定元素
    drainTo(Collection<? super E> c):队列转化为集合
2.2.1.1 ArrayBlockingQueue

ArrayBlockingQueue是一个由数组支持的有界阻塞队列。

  • 底层是基于数组的BlockingQueue的实现。
  • 容纳大小是固定的,不可扩展。
  • 线程安全的。
  • 不接受 null 元素。
  • 公平性 (fairness)可以在构造函数中指定,如果为true,则按照 FIFO 顺序访问插入或移除时受阻塞线程的队列;如果为 false,则访问顺序是不确定的。

实例代码:

public static void arrayBlockingQueue() throws InterruptedException {BlockingQueue<String> blockingQueue = new ArrayBlockingQueue(10);blockingQueue.add("2");blockingQueue.offer("3");blockingQueue.put("1");blockingQueue.remove("1");blockingQueue.poll();blockingQueue.take();blockingQueue.peek();blockingQueue.contains("2");blockingQueue.drainTo(new LinkedList<>());
}
2.2.1.2 LinkedBlockingQueue

LinkedBlockingQueue是一个单向链表实现的阻塞队列,可以定义为无界队列也可以是有界队列。这里用了两个锁,读写可以同时进行,条件满足时,往队尾加入,对头出列。

代码示例

// 单向链表
static class Node<E> {E item;/*** One of:* - the real successor Node* - this Node, meaning the successor is head.next* - null, meaning there is no successor (this is the last node)*/Node<E> next;Node(E x) { item = x; }
}
public static void linkedBlockingQueue() throws InterruptedException {BlockingQueue<String> blockingQueue = new LinkedBlockingQueue();blockingQueue.put("1");blockingQueue.poll();blockingQueue.offer("e");blockingQueue.remove();
}

2.2.2 Deque

Deque接口是“double ended queue”的缩写(通常读作“deck”),即双端队列,支持在队列的两端插入和删除元素,继承Queue接口。大多数的实现对元素的数量没有限制,但这个接口既支持有容量限制的deque,也支持没有固定大小限制的。

Deque接口定义了在两端访问元素的方法,主要包括insert、remove和examine。和Queue定义一样,所有这些方法存在两种形式:一种如果操作失败则抛出异常,另一种则返回一个特殊值(null或false)。后者主要是为有容量限制的队列实现的。
Deque的12种方法总结如下:

. First Element (Head) Last Element (Tail)
. Throws exception Special value Throws exception Special value
Insert addFirst(e) offerFirst(e) addLast(e) offerLast(e)
Remove removeFirst() pollFirst() removeLast() pollLast()
Examine getFirst() peekFirst() getLast() peekLast()

当deque用作queue时,则表现出FIFO的行为,元素从队尾加入,在队首移除,从Queue接口继承来的方法和Deque中的一些方法等

2.2.2.1 LinkedBlockingDeque

LinkedBlockingDeque是双向链表实现的阻塞队列,可以被当作堆栈、双端队列进行操作。

代码示例

// 双向链表结构
/** Doubly-linked list node class */
static final class Node<E> {/*** The item, or null if this node has been removed.*/E item;/*** One of:* - the real predecessor Node* - this Node, meaning the predecessor is tail* - null, meaning there is no predecessor*/Node<E> prev;/*** One of:* - the real successor Node* - this Node, meaning the successor is head* - null, meaning there is no successor*/Node<E> next;Node(E x) {item = x;}
}
public static void linkedBlockingDeque() throws InterruptedException {BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>();blockingQueue.put("1");blockingQueue.poll();blockingQueue.offer("e");blockingQueue.remove();
}

3、Map

Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。

3.1 Hashtable

Hashtable简介:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,只有hashtable是继承自Dictionary抽象类的,hashMap和treeMap都继承自AbstractMap抽象类,LinkedHashMap继承自hashMap。

  • 底层为一个Entry数组。
  • 传入的值不能为null。
  • 它是线程安全的。
// 源码add()
public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;
}

实例代码

public static void hashTable() {Hashtable map = new Hashtable();map.put("1", "2");map.get("1");map.remove("1");
}

3.2 HashMap

HashMap的实现了Map接口。

  • 它是无序的,非同步的。
  • key值唯一,最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。
  • 底层是一个Node数组,数组默认初始大小是16。
  • Node数组的元素默认是一个链表,当链表长度>=8时,会转换成一颗红黑树。
  • 最大容积是2^30, 有阈值、负载系数等。。
  • 添加元素时,先根据key值计算得出hash值,根据hash值进行运算得出数组的下标,最后将元素插入该数组下标对应的node链表末尾。

名词解析
红黑树。一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。
通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
阈值。当元素长度超过阈值时,会自动扩张数组大小。阈值初始值为:160.75=12,16为数组默认长度,0.75为默认负载系数;阈值后面扩充公式:当前阈值2=新阈值。
node数组扩充公式。当前数组大小 * 2=新数组大小。

// 扩充代码
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;...}

示例代码

public static void hashMap() {HashMap<String, String> hashMap = new HashMap<>();for (int i = 0; i < 14; i++) {if (i == 12) {int a = 1;System.out.println(a+"");}hashMap.put("" + i, "2");}
}

3.2.1 LinkedHashMap

LinkedHashMap继承了HashMap。

  • 它是有序的。
  • key和value均允许为空,非同步的。
  • 底层维护了首尾两个Entry双向链表,且Entry继承了HashMap的Node类。
  • 除了底层数据结构与HashMap不同之外,其他大致相同。
// LinkedHashMap底层数据结构
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}
}

实例代码

public static void linkedHashMap() {LinkedHashMap<Integer, String> l = new LinkedHashMap<>();l.put(1, "a");l.put(2, "b");System.out.println(l);
}

3.3 TreeMap

TreeMap实现了NavigableMap,间接实现了SortedMap接口。

  • 它是有序的,默认根据key按升序排序,可以自定义比较器。
  • TreeMap不允许key的值为null,非同步的。
  • 底层是一颗红黑树。
private final Comparator<? super K> comparator;
private transient Entry<K,V> root;// 根节点static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;Entry<K,V> left;Entry<K,V> right;Entry<K,V> parent;boolean color = BLACK;...
}

示例代码

public static void treeMap() {TreeMap<Integer, String> treeMap = new TreeMap<>();treeMap.put(2, "b");treeMap.put(1, "a");treeMap.put(4, "d");treeMap.put(3, "c");System.out.println(treeMap);}

3.4 拓展知识

  • IdentityHashMap
    IdentityHashMap 是一个实现了 Map 接口的哈希表,它使用了引用相等来替代对象相等,即只有 k1 == k2 的情况下,才认为这两个对象相等。参考链接 Java8 - IdentityHashMap源码
  • SortedMap
    SortedMap 接口继承自 Map 接口,提供了按照 Key 排序的功能,即 keySet、values、entrySet 结果集有序。参考链接 Java集合学习十三 SortedMap
  • NavigableMap
    NavigableMap扩展了 SortedMap,具有了针对给定搜索目标返回最接近匹配项的导航方法。参考链接 Java集合之NavigableMap与NavigableSet接口
  • WeakHashMap
    WeakHashMap,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值。参考链接 解析WeakHashMap与HashMap的区别详解

Java集合总结(架构师之路 )相关推荐

  1. java 资深_Java架构师之路:从Java码农到资深架构师

    写在开篇 不管是开发.测试.运维,每个技术人员心里都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使我们不断地努力和提升自己. 然而" ...

  2. 从0到1—JAVA大数据架构师之路

    第一阶段:java基础及进阶 第二阶段:数据库VUE&SSM 第三阶段:SSM架构及后端开发项目 第四阶段:微服务之SpingCloudAlibaba 第五阶段:微服务之Spingcloud ...

  3. python爬虫架构师之路_一位资深 架构师大牛给予Java技术提升的学习路线建议

    一位资深 架构师大牛给予Java技术提升的学习路线建议 对于工作多年的程序员而言,日后的职业发展无非是继续专精技术.转型管理和晋升架构师三种选择. 架构师在一家公司有多重要.优秀架构师需要具备怎样的素 ...

  4. Java高级架构师之路核心知识整理

    小编整理出一篇Java高级架构师之路的核心知识,同时也是面试时面试官必问的知识点,篇章也是包括了很多知识点,其中包括了有基础知识.Java集合.JVM.多线程并发.spring原理.微服务.Netty ...

  5. java架构师之路:JAVA程序员必看的15本书的电子版下载地址

    java架构师之路:JAVA程序员必看的15本书的电子版下载地址 作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从.我想就我自己读过的技术书籍中挑选出来一 ...

  6. 架构师变形记:讲述Java码农到年薪100万架构师之路

    最近有不少朋友问我怎样才能成为年薪百万的架构师,我听到他这样问,首先想到的是什么样的人才可以称之为架构师,然后我给他总结了他需要攻克的3个难点: 1.接触不到一线实战架构设计,尤其是有一定的技术深度和 ...

  7. java架构师什么学校好_Java架构师之路:年薪八十万的架构师课程

    原标题:Java架构师之路:年薪八十万的架构师课程 不管是开发.测试.运维,每个技术人员心里都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使 ...

  8. JAVA架构师之路十五:设计模式之策略模式

    JAVA架构师之路十四:设计模式之模板模式 策略模式 1. 策略模式 2. 优惠券案例 3. 支付案例 人生的游戏不在于拿了一副好牌,而在于怎样去打好坏牌,世上没有常胜将军,勇于超越自我者才能得到最后 ...

  9. JAVA架构师之路十六:设计模式之责任链模式

    JAVA架构师之路十五:设计模式之策略模式 责任链模式 1. 责任链模式 2. 登陆案例 3. 登陆案例优化 人生的游戏不在于拿了一副好牌,而在于怎样去打好坏牌,世上没有常胜将军,勇于超越自我者才能得 ...

最新文章

  1. html 表格自动计算,HTML表格中的JavaScript计算
  2. 石头扫地机器人加速异响_米家扫地机器人有异响怎么办
  3. Kali Linux渗透测试实战 2.2 操作系统指纹识别
  4. MyBatis-学习笔记10【10.JNDI扩展知识】
  5. 计算机基础知识教程职称怎么计算,2017年职称计算机考试基础知识教程详解(二十)...
  6. Jackson快速入门
  7. 高考python必考题目_假如高考考python编程,这些题目你会几个呢?
  8. sql datetime字段 取年月日_写一手好SQL,你该从哪里入手?
  9. php web长时间不操作退出,Ecshop管理员登陆后台后短时间不操作自动退出的解决方法...
  10. Linux的Cache Memory(缓存内存)机制
  11. 472. 连接词(每日一难phase2--day24)
  12. 带通 带阻滤波器 幅频响应_方程推导:二阶有源带通滤波器设计!(内附教程+原理图+视频+代码下载)...
  13. 1、AD创建模板和导入
  14. 免费网站流量统计服务汇总
  15. 程序猿头头(js数组reverse,sort,concat,slice, splice)
  16. 自学简单编程可行吗?
  17. java编译器eclipse_Java 调用 Eclipse的编译器 JDT
  18. 【Python】原来处理大文件也可以这么简单?
  19. poiExcel格式设置,很好用,感谢大佬
  20. 【分库分表】企业级分库分表实战方案与详解(MySQL专栏启动)

热门文章

  1. python excel数据处理功能模块_Python 之Excel 数据处理
  2. 【日常练习】递增数列 【迭代加深】
  3. 根据车辆品牌获取品牌所属公司,车标logo,创建年份等基本信息
  4. Plecs电力电子仿真专业教程-第一季 补充课程 Plecs的安装教程与软件下载
  5. 2021特种工(塔式起重机)模拟题集及答案解析
  6. python-opencv实现图像超像素分割(SLIC、SEEDS、LSC)
  7. php上传文件存本地
  8. 数据结构-1.单链表的初始化
  9. ip地址错误解决方法
  10. 【历史上的今天】2 月 10 日:QQ 诞生;IBM 电脑击败人类象棋冠军;谷歌光纤发布