星期四, 二月 18, 2016

List之ArrayList源码分析

ArrayList内部使用一个Object[]数组来保存元素。源码版本为JDK1.7.0_75.

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable,java.io.Serializable
ArrayList<E>可以看出它是支持泛型的,它继承了AbstractList,该类提供了List接口的默认实现;List接口定义了list必须实现的方法;RandomAccess是一个标记接口,接口内没有定义任何内容;实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝;实现java.io.Serializable接口可以启用序列化功能,这个也是一个标记接口,接口内也没有定义任何内容,仅用于标识可序列化的语义。

成员变量
    private static final long serialVersionUID = 8683452581122892189L;

    /**
* 默认初始长度
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
* 共享的空数组,用于无参构造实例
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
* 存储arraylist元素的bufferarraylist的容量为该数组的长度。当arraylist为空且
*   elementData==EMPTY_ELEMENTDATA时,添加第一个元素时,arraylist的长度会扩展到
*   DEFAULT_CAPACITY
* The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;

    /**
* arraylist的长度(包含的元素数目)
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;
elementData数组存储ArrayList中的元素,size为数组长度。
其中,transient关键字用来表示一个域不是该对象串行化(序列化)的一部分。当一个对象被串行化(序列化)时,transient型变量不包括在串行化(序列化)表示中。通俗地讲,如果用transient修饰一个变量,当对象被存储时,该变量的值不需要维持,不需要为给变量分配内存。
1. transient的作用及使用方法
      我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。
      然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。
      总之,java transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。


构造函数
    /**
* 构造给定数组大小的空数组
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /**
* 构造未指定数组大小的空数组,此时elementData=EMPTY_ELEMENTDATA
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
* 构造指定数组大小及元素的数组
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

方法:
trimToSize中的modCount为父类AbstractList的成员,"The number of times this list has been <i>structurally modified</i>"记录list结构修改次数。
    /**
* arraylist的容量修剪到数组的长度。应用该方法可以减少arraylist实例的内存。
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }


扩充arraylist的容量,至少扩充到原来的1.5
    /**
* 扩充arraylist的容量
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param   minCapacity   the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
* 扩充容量,确保它至少扩充到原来的1.5倍。
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int 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) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }


方法sizeisEmpty都是根据size判断,花费O(1)时间,indexOf方法中,首先判断要搜索的元素是否为空,若为空则遍历数组是否存在空值,有则返回对应的下表,否则返回-1;若元素不为空,同样是遍历数组,使用equal方法判断数组中是否有相等的元素。lastIndexOf方法与indexOf类似,只不过遍历方式是从后向前。contains方法通过判断indexOf方法查找该元素。
    /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Returns <tt>true</tt> if this list contains no elements.
     *
     * @return <tt>true</tt> if this list contains no elements
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Returns <tt>true</tt> if this list contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this list contains
     * at least one element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
    * or -1 if there is no such index.
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }


clone方法首先调用父类的clone方法返回一个对象的副本,将所返回的对象的elementData数组赋值为原对象elementData的内容,将副本的modCount设置为0.
该方法返回ArrayList实例的浅副本,即不复制这些元素本身。
    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            @SuppressWarnings("unchecked")
                ArrayList<E> v = (ArrayList<E>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError();
        }
    }

toArray方法返回elementData数组的副本,而不是返回elementData本身。
    /**
     * Returns an array containing all of the elements in this list
     * in proper sequence (from first to last element).
     *
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this list.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     *
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this list in
    *         proper sequence
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

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

addremove特定下标的元素,add的话,注意要先扩充数组容量,若,remove的话最后记得将要删除的位置设置为null,让GC回收垃圾,两个方法都是通过方法system.arraycopy移动数组位置。
添加和删除元素方法不是同步的,因此如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了数组,那么该数组必须保持外部同步,在网上查到,可以通过Collections.synchronizedList方法将该数组包装起来。
    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }


clear方法并没有修改elementData的长度,只是将其内容设置null,让GC回收空间,并设size0.
    /**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }


removeAllretainAll方法,removeAll是删除数组中包含指定集合的元素,retainAll是只保留在指定集合中的元素,数组的其他元素将删除。
    /**
     * Removes from this list all of its elements that are contained in the
     * specified collection.
     *
     * @param c collection containing elements to be removed from this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean removeAll(Collection<?> c) {
        return batchRemove(c, false);
    }

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * @param c collection containing elements to be retained in this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        return batchRemove(c, true);
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
sizeisEmptygetsetiteratorlistIterator操作需要O1)时间,addremove等操作大都以线性时间运行。
参考:

查看JDK源码

Eclipse中查看JDK类库的源代码!!!

 

设置:

 

1. "window"-> "Preferences" -> "Java" -> "Installed JRES"

 

2.此时"Installed JRES"右边是列表窗格,列出了系统中的 JRE 环境,选择你的JRE,然后点边上的 "Edit..." 会出现一个窗口(Edit JRE)

 

3.选中rt.jar文件的这一项:"c:\program files\java\jre_1.5.0_06\lib\rt.jar"

左边的"+" 号展开它,

 

4.展开后,可以看到"Source Attachment:(none)",点这一项,点右边的按钮"Source Attachment...", 选择你的JDK目录下的 "src.zip"文件

 

5.一路点"ok",结束。

 

dt.jar是关于运行环境的类库,主要是swing的包

tools.jar是关于一些工具的类库

rt.jar包含了jdk的基础类库,也就是你在java doc里面看到的所有的类的class文件

 

 

 

使用:

设置完成后,按住ctrl键再用鼠标单击某一个jdk方法名或类名,便能看到该方法的源代码了。此外按F3也能实现。

 

Office 2013 激活方法

参考:

注:该方法针对office批量版(VOL版),区分2013零售版和批量版的方法:
参考:

若你发现office为零售版,也没关系,可以通过工具将其转换为批量版,下载转换工具(http://pan.baidu.com/s/1b1PLX)解压到桌面,双击按1切换到vol
1、任意打开office2013的一个产品,比如word的账户,点击更改产品密钥,输入激活码
YC7DK-G2NP3-2QQC3-J6H88-GVGXT,安装。
2、新建txt文本输入以下代码:
@echo off
cd D:\程序文件\office2013\安装文件\Office15
cscript ospp.vbs /sethst:127.0.0.2
cscript ospp.vbs /act
cscript ospp.vbs /dstatus
cscript ospp.vbs /remhst
pause
(注:D:\程序文件\office2013\安装文件\Office15为你安装office目录。)
保存txt文档,修改txt文档格式为bat文件。
3、用管理员身份运行bat文件即可。

office安装位置不在c盘,可能出现以下的错误:
提示找不到脚本文件c:\windows\system32\ospp.vbs,这个文件在office2013安装位置的Office15文件夹下,只要将脚本ospp.vbs拷贝到c:\windows\system32\下,在重新以管理员身份运行bat,即可成功激活。

激活过程中cscript ospp.vbs命令详解 http://www.ihacksoft.com/ospp-vbs.html
Office 2013激活过程中我们经常会用到cscript ospp.vbs这个命令。那么,很有必要来了解一下,ospp.vbs到底是什么文件?Cscript.exe是脚本运行引擎,这里就不多介绍了。ospp全称为:Office Software Protection Platformvbs大家都知道是脚本文件,所以得出结论,ospp.vbs就是:Office软件保护平台脚本。它是目前Office自身提供的激活管理工具。
ospp.vbs文件在哪里?
该脚本位于%安装目录%\ Program Files文件\微软Office \ Office15文件夹中。如果您运行的是32Office 201364位操作系统,该脚本位于%安装目录%\程序文件(x86\微软Office \ Office15文件夹中。
ospp.vbs命令介绍
命令有很多,不一一全部介绍了,说说几个激活过程中的常用命令。
cscript ospp.vbs /dstatus
显示当前已安装产品密钥的许可证信息。可以查看到自已安�b的版本有多少个序列号。

cscript ospp.vbs /unpkey:xxxxx
卸载已安装的产品密钥。后面的数字是密钥的最后5位数。

cscript ospp.vbs /inpkey:xxxxx……
安装、替换现有的产品密钥。和上面的过程刚好相反。
cscript ospp.vbs /sethst:x.x.x.x
设置KMS主机名。一般为IP地址。
cscript ospp.vbs /act
激活当前安装的Office
cscript ospp.vbs /remhst
删除KMS主机名。

其中,KMS(密钥管理服务)允许在本地网络上激活产品,这样单台计算机不必连接至Microsoft便可激活产品。

密钥管理服务(Key Management ServiceKMS), "KMS"是微软对"大客户"(VL即:VOL)提供的Microsoft产品激活方式之一。在适用此方式的Microsoft产品中,无论是中文和外文,还是32位和64位,均可通过"KMS"服务器实施激活。"KMS"激活技术规定:激活后有效使用期限为"180天"。届时须重新激活,又是一轮"180天"(如此循环往复)
而实际情况中,很多KMS服务器其实为私服,或者软件在本地模拟KMS服务,以达到激活







319. Bulb Switcher

There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the nth round, you only toggle the last bulb. Find how many bulbs are on after n rounds.
Example:
Given n = 3.
At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off].
So you should return 1, because there is only one bulb is on.
通过以下代码可以找到规律:
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
    int bulbSwitch(int n) {
        int cnt=0;
vector<int>v=vector<int>(n+1,0);
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j+=i)v[j]++;
}
for(int i=1;i<=n;i++)
if(v[i]&1)cnt++;
return cnt;
    }
};
int main(){
Solution test=Solution();
for(int i=1;i<=50;i++)
cout<<test.bulbSwitch(i)<<endl;
system("pause");
return 0;
}
可以看出,依次输出31527394.。。。。(如果使用以上代码,会超时)

在网上搜到的解题思路:
题目的意思是n个灯泡,第i次,第i*1,i*2i*k个灯被切换,以n=6为例,
1=1×1,指第一次round
2=1×22×1,指第12round
3=1×33×1,指第13round
4=1×42×24×1,指第124round
5=1×55×1,指第15round
6=1×62×33×26×1,指第1236round
class Solution {
public:
    int bulbSwitch(int n) {
        return (int)sqrt(n);
    }
};