`
小皮球
  • 浏览: 33921 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

LIST 实现

阅读更多
ArrayList是List接口的一个可变长数组实现。实现了所有List接口的操作,并允许存储null值。除了没有进行同步,ArrayList基本等同于Vector。在Vector中几乎对所有的方法都进行了同步,但ArrayList仅对writeObject和 readObject进行了同步,其它比如add(Object)、remove(int)等都没有同步。

1.存储
ArrayList使用一个Object的数组存储元素。
private transient Object elementData[];
ArrayList实现了java.io.Serializable接口,这儿的transient标示这个属性不需要自动序列化。下面会在 writeObject()方法中详细讲解为什么要这样作。

2.add和remove
Java 代码  收藏代码
   1. public boolean add(Object o) {  
   2. ensureCapacity(size + 1); // Increments modCount!!  
   3. elementData[size++] = o;  
   4. return true;  
   5. }   

public boolean add(Object o) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = o;
return true;
} 






注意这儿的ensureCapacity()方法,它的作用是保证elementData数组的长度可以容纳一个新元素。在“自动变长机制”中将详细讲解。
Java 代码  收藏代码

 
 1. public Object remove(int index) {  
   2. RangeCheck(index);  
   3. modCount++;  
   4. Object oldValue = elementData[index];  
   5. int numMoved = size - index - 1;  
   6. if (numMoved > 0)  
   7. System.arraycopy(elementData, index+1, elementData, index,  
   8. numMoved);  
   9. elementData[--size] = null; // Let gc do its work  
  10. return oldValue;  
  11. }   


public Object remove(int index) {
RangeCheck(index);
modCount++;
Object oldValue = elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
} 






RangeCheck()的作用是进行边界检查。由于ArrayList采用一个对象数组存储元素,所以在删除一个元素时需要把后面的元素前移。删除一个元素时只是把该元素在elementData数组中的引用置为null,具体的对象的销毁由垃圾收集器负责。
modCount的作用将在下面的“iterator()中的同步”中说明。
注:在前移时使用了System提供的一个实用方法:arraycopy(),在本例中可以看出System.arraycopy()方法可以对同一个数组进行操作,这个方法是一个native方法,如果对同一个数组进行操作时,会首先把从源部分拷贝到一个临时数组,在把临时数组的元素拷贝到目标位置。

3.自动变长机制
在实例化一个ArrayList时,你可以指定一个初始容量。这个容量就是elementData数组的初始长度。如果你使用:

ArrayList list = new ArrayList();

则使用缺省的容量:10。

public ArrayList() {
this(10);
}

ArrayList提供了四种add()方法,
Java 代码  收藏代码

  
1. public boolean add(Object o)  
   2.   
   3. public void add(int index, Object element)  
   4.   
   5. public boolean addAll(Collection c)  
   6.   
   7. public boolean addAll(int index, Collection c)   

public boolean add(Object o)

public void add(int index, Object element)

public boolean addAll(Collection c)

public boolean addAll(int index, Collection c) 






在每一种add()方法中,都首先调用了一个ensureCapacity(int miniCapacity)方法,这个方法保证elementData数组的长度不小于miniCapacity。ArrayList的自动变长机制就是在这个方法中实现的。
Java 代码  收藏代码
   1. public void ensureCapacity(int minCapacity) {  
   2. modCount++;  
   3. int oldCapacity = elementData.length;  
   4. if (minCapacity > oldCapacity) {  
   5. Object oldData[] = elementData;  
   6. int newCapacity = (oldCapacity * 3)/2 + 1;  
   7. if (newCapacity < minCapacity)  
   8. newCapacity = minCapacity;  
   9. elementData = new Object[newCapacity];  
  10. System.arraycopy(oldData, 0, elementData, 0, size);  
  11. }  
  12. }   


public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = new Object[newCapacity];
System.arraycopy(oldData, 0, elementData, 0, size);
}
} 






从这个方法实现中可以看出ArrayList每次扩容,都扩大到原来大小的1.5倍。
每种add()方法的实现都大同小异,下面给出add(Object)方法的实现:
Java 代码  收藏代码

  1. public boolean add(Object o) {  
   2. ensureCapacity(size + 1); // Increments modCount!!  
   3. elementData[size++] = o;  
   4. return true;  
   5. }  

public boolean add(Object o) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = o;
return true;
}






4.iterator() 中的同步
在父类AbstractList中定义了一个int型的属性:modCount,记录了ArrayList结构性变化的次数。

protected transient int modCount = 0;

在ArrayList的所有涉及结构变化的方法中都增加modCount的值,包括:add()、remove()、addAll()、 removeRange()及clear()方法。这些方法每调用一次,modCount的值就加1。
注:add()及addAll()方法的modCount的值是在其中调用的ensureCapacity()方法中增加的。

AbstractList中的iterator()方法(ArrayList直接继承了这个方法)使用了一个私有内部成员类Itr,生成一个Itr对象(Iterator接口)返回:

public Iterator iterator() {
return new Itr();
}


Itr实现了Iterator()接口,其中也定义了一个int型的属性:expectedModCount,这个属性在Itr类初始化时被赋予 ArrayList对象的modCount属性的值。

int expectedModCount = modCount;

注:内部成员类Itr也是ArrayList类的一个成员,它可以访问所有的AbstractList的属性和方法。理解了这一点,Itr类的实现就容易理解了。

在Itr.hasNext()方法中:

public boolean hasNext() {
return cursor != size();
}


调用了AbstractList的size()方法,比较当前光标位置是否越界。

在Itr.next()方法中,Itr也调用了定义在AbstractList中的get(int)方法,返回当前光标处的元素:
Java 代码  收藏代码

 
 1. public Object next() {  
   2. try {  
   3. Object next = get(cursor);  
   4. checkForComodification();  
   5. lastRet = cursor++;  
   6. return next;  
   7. } catch(IndexOutOfBoundsException e) {  
   8. checkForComodification();  
   9. throw new NoSuchElementException();  
  10. }  
  11. }   

public Object next() {
try {
Object next = get(cursor);
checkForComodification();
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
} 





注意,在next()方法中调用了checkForComodification()方法,进行对修改的同步检查:
Java 代码  收藏代码

   1. final void checkForComodification() {  
   2. if (modCount != expectedModCount)  
   3. throw new ConcurrentModificationException();  
   4. }  

final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}





现在对modCount和expectedModCount的作用应该非常清楚了。在对一个集合对象进行跌代操作的同时,并不限制对集合对象的元素进行操作,这些操作包括一些可能引起跌代错误的add()或remove()等危险操作。在AbstractList中,使用了一个简单的机制来规避这些风险。这就是modCount和expectedModCount的作用所在。

5.序列化支持
ArrayList实现了java.io.Serializable接口,所以ArrayList对象可以序列化到持久存储介质中。ArrayList的主要属性定义如下:

private static final long serialVersionUID = 8683452581122892189L;

private transient Object elementData[];

private int size;


可以看出serialVersionUID和size都将自动序列化到介质中,但elementData数组对象却定义为transient了。也就是说 ArrayList中的所有这些元素都不会自动系列化到介质中。为什么要这样实现?因为elementData数组中存储的“元素”其实仅是对这些元素的一个引用,并不是真正的对象,序列化一个对象的引用是毫无意义的,因为序列化是为了反序列化,当你反序列化时,这些对象的引用已经不可能指向原来的对象了。所以在这儿需要手工的对ArrayList的元素进行序列化操作。这就是writeObject()的作用。
Java 代码  收藏代码

  1. private synchronized void writeObject(java.io.ObjectOutputStream s)  
   2. throws java.io.IOException{  
   3. // Write out element count, and any hidden stuff  
   4. s.defaultWriteObject();  
   5. // Write out array length  
   6. s.writeInt(elementData.length);  
   7. // Write out all elements in the proper order.  
   8. for (int i=0; i<size; i++)  
   9. s.writeObject(elementData[i]);  
  10. }   


private synchronized void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
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]);
} 






这样元素数组elementData中的所以元素对象就可以正确地序列化到存储介质了。
对应的readObject()也按照writeObject()方法的顺序从输入流中读取:
Java 代码  收藏代码

  
1. private synchronized void readObject(java.io.ObjectInputStream s)  
   2. throws java.io.IOException, ClassNotFoundException {  
   3. // Read in size, and any hidden stuff  
   4. s.defaultReadObject();  
   5. // Read in array length and allocate array  
   6. int arrayLength = s.readInt();  
   7. elementData = new Object[arrayLength];  
   8. // Read in all elements in the proper order.  
   9. for (int i=0; i<size; i++)  
  10. elementData[i] = s.readObject();  
  11. }
分享到:
评论

相关推荐

    C# List实现行转列的通用方案

    C# List实现行转列的通用方案 本文将介绍使用C# List实现行转列的通用方案,通过使用System.Linq.Dynamic动态LINQ库来完成行转列功能,并且介绍了过滤功能,具有很好的参考价值。 1. 行转列的需求分析 在报表统计...

    STL -list实现02

    STL list实现02,其他容器的实现,依次类推。看不懂的C基础太差,别想C++某些原理了

    list实现的购物车

    综上所述,"list实现的购物车"项目结合了Python的基础数据结构和web开发中的cookie技术,通过这些工具,我们可以创建一个基本的、能在用户会话间持久化的购物车系统。然而,实际的电商系统可能还需要考虑更多的细节...

    List实现 数据结构 模板

    通过使用模板,我们可以创建通用的List实现,适应不同类型的元素,提高代码的可复用性。在C++中,模板是一种强大的工具,能够帮助我们编写出高效、灵活的代码。通过实践这三种List实现,不仅可以提升编程技能,还能...

    透明列表框MFClist实现背景透明

    本示例“透明列表框MFClist实现背景透明”正是针对这一需求提供的一个解决方案。它允许用户在不干扰其他界面元素的情况下,使列表框的背景变得透明,从而提升应用程序的界面美观度和用户体验。 首先,我们需要理解...

    用List实现的完整购物车源代码

    总的来说,使用List实现购物车功能是一种简单直观的方法,尤其适合初学者理解和实践。然而,随着需求的复杂性增加,可能需要引入更复杂的数据结构和设计模式来优化性能和可扩展性。在项目中,我们需要根据具体需求和...

    牛逼的list实现

    牛逼的list实现

    安卓listview相关相关-通过Animation-list实现将图片进行逐帧动画的播放.rar

    本资源"安卓listview相关相关-通过Animation-list实现将图片进行逐帧动画的播放.rar"主要讲解了如何在ListView的项视图中利用Animation-list实现图片的逐帧动画效果。这种技术常见于游戏或者动态图标的设计中,可以...

    java 简单实例 list实现bubble sort

    以下是一个简化的示例代码片段,演示了如何使用Java List实现冒泡排序: ```java import java.util.ArrayList; import java.util.List; public class BubbleSortExample { public static void main(String[] args...

    简单的图书管理系统,增删改查,用LISt实现,java新手看

    常见的List实现类有ArrayList和LinkedList,其中ArrayList基于动态数组,适合随机访问,而LinkedList基于双向链表,适合插入和删除操作。 二、图书管理系统的数据模型 图书管理系统的核心是图书类(Book),通常...

    java使用list实现数据库的like功能

    在Java编程中,使用List实现数据库的“LIKE”功能,主要是为了模拟数据库中的模糊查询操作。这个功能在处理大量数据时非常有用,尤其是当用户输入的部分关键词需要匹配数据库中对应的字段时。下面将详细解释如何使用...

    CheckBoxList实现单选 C#(WEB)

    本篇将详细介绍如何在C#环境下,针对ASP.NET Web Forms应用,实现CheckBoxList控件的单选效果。 首先,我们需要理解CheckBoxList的基本结构。CheckBoxList控件是基于HTML的多选框列表,每个选项由一个CheckBox控件...

    vc关于窗口的list实现右键菜单

    本篇将详细介绍如何在VC++中通过List控件实现右键菜单。 首先,我们需要了解VC++中的基本概念。MFC(Microsoft Foundation Classes)是微软提供的一个C++类库,用于简化Windows应用程序的开发。在这个环境中,我们...

    C++ 自实现的List

    在这个自定义的List实现中,我们可能包含了基本的添加元素(push)、删除元素(pop)以及赋值和加法操作。下面将详细解释这些概念和操作。 **1. 结构设计** 自定义的List通常由节点(Node)组成,每个节点包含一个...

    用python中的list实现CRUD

    主要用python实现对list进行CRUD的操作

    重写C++的list实现增 删 改的功能

    本篇文章将深入探讨如何重写C++的`list`,并实现增、删、改的基本操作。 首先,我们需要了解`std::list`的核心概念。它是一个模板类,可以存储任何类型的对象,只要这些对象能够被复制或移动。`std::list`通常由...

    HarmonyOS应用开发-圆角list实现.docx

    为实现圆角效果,我们需要关注`list`及其内部的`list-item`元素。 ```html &lt;list class="topList_corner_round_bg" scrolleffect="no"&gt; &lt;!-- ... --&gt; &lt;/list&gt; &lt;list class="middleList_corner_round_bg"&gt; &lt;!-- .....

    android之animation-list实现的简单粘稠加载效果使用demo

    `animation-list`是Android系统提供的一种用于创建帧动画的视图组件,常用来实现如加载、旋转、弹跳等效果。本教程将深入探讨如何使用`animation-list`来创建一个简单的粘稠加载效果。 一、animation-list概述 `...

    Android 用Animation-list实现逐帧动画

    本篇将深入讲解如何利用`Animation-list`在Android中实现逐帧动画。 一、`Animation-list`基础 `Animation-list`是Android XML动画资源的一种类型,它定义了一组子项(通常为ImageView的源),这些子项按照指定的...

    skiplist跳表C++实现

    跳表(Skip List)是一种高效的动态查找数据结构,它的设计灵感来源于随机化算法。在C++中实现跳表,可以利用其高效的插入、删除和查找操作,尤其适用于大规模数据的处理。下面我们将深入探讨跳表的基本原理、C++...

Global site tag (gtag.js) - Google Analytics