zoukankan      html  css  js  c++  java
  • [改善Java代码]在明确的场景下,为集合指定初始容量

    我们经常使用ArrayList,Vector,Hashmap等集合,一般都是直接用new跟上类名声明出一个集合来,然后使用add,remove,等方法进行操作,而且因为它们是自动管理长度的,所以不用我们特别费心超长问题,这确实是一个非常好的优点,但也有我们需要注意的事项.

    下面以ArrayList为例深入了解一下Java是如何实现长度的动态管理的,先从add方法的阅读开始.

    1 public boolean add(E e) {    
    2         ensureCapacity(size + 1);     
    3         elementData[size++] = e;    
    4         return true;    
    5     }    

    我们知道ArrayList是一个大小可变的数组,但它在底层使用的是数组存储(也就是elementData变量),而且数组是定长的,要实现动态长度必然要进行长度的扩展,ensureCapacity方法提供了此功能,代码如下:

     1     public void ensureCapacity(int minCapacity) {    
     2         modCount++;         //修改计数器  
     3         int oldCapacity = elementData.length;      
     4         //当前需要的长度超过了数组长度,进行扩容处理  
     5         if (minCapacity > oldCapacity) {    
     6             Object oldData[] = elementData;    
     7             //新的容量 = 旧容量 * 1.5 + 1  
     8             int newCapacity = (oldCapacity * 3)/2 + 1;    
     9                 if (newCapacity < minCapacity)    
    10                     newCapacity = minCapacity;    
    11           //数组拷贝,生成新的数组   
    12           elementData = Arrays.copyOf(elementData, newCapacity);    
    13         }    
    14     }  

    注意看新数组的长度计算方法,并不是增加一个元素,elementData的长度就加1,而是在达到了elementData长度的临界点时,才将elementData扩容1.5把倍,这样实现有什么好处呢?好处就是避免了多次调用copyOf()方法的性能开销,否则每增加一个元素都要扩容一次,那性能岂不是非常的糟糕.

    为什么是1.5倍呢,因为一次扩容太大,占用的内存也就越大,浪费的内存也就越多(1.5倍扩容,最多浪费33%的数组空间,而2.5倍扩容则最多浪费60%的内存),而扩容太小(比如每次扩容1.1倍),则需要多次对数组重新分配内存,性能消耗严重,经过测试验证,扩容1.5倍即满足了性能要求,也减少了内存消耗.

    elementData的默认长度是10,如果我们使用默认的方式生命ArrayList,如new ArrayList(),则elementData的初始长度就是10.我们来看ArrayList的无参构造:

     1     // ArrayList无参构造函数。默认容量是10。    
     2     public ArrayList() {    
     3         this(10);    
     4     }    
     5     // ArrayList带容量大小的构造函数。    
     6     public ArrayList(int initialCapacity) {    
     7         super();    
     8         if (initialCapacity < 0)    
     9             throw new IllegalArgumentException("Illegal Capacity: "+    
    10                                                initialCapacity);    
    11         // 新建一个数组    
    12         this.elementData = new Object[initialCapacity];    
    13     }  

    默认初始化时声明了一个长度为10的数组 在通过add方法增加第11个元素时,ArrayList类就自动扩展了,新的elementData数组长度就是(10*3)/2 +1 也就是16,当增加到第17个元素时再次扩容为(16*3)/2+1 也就是25,以此类推,实现了ArrayList的动态数组管理.

  • 相关阅读:
    Ubuntu14.0.4 64位 ADT 连接手机调试问题
    Ubuntu14.0.4 64位安装ADT问题
    Uubntu scrot 的简单使用
    Ubuntu14.0.4 64位安装Chrome浏览器
    Android DatePickerDialog 只选择年月
    Java 正则提取数字串
    客户端HttpClient处理 Servlet Gzip
    Ext常用Tool
    python使用 requirements.txt 管理所需的包
    PyQt5安装及ModuleNotFoundError: No module named 'PyQt5'问题解决
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5422175.html
Copyright © 2011-2022 走看看