ArrayList实现可变数组的原理:

  当元素超出数组内容,会产生一个新数组,将原来数组的数据复制到新数组中,再将新的元素添加到新数组中。

  ArrayList:是按照原数组的50%来延长,构造一个初始容量为10的空列表

用ArrayList模拟数组:

package iterater.patten.design;

//探索ArrayList实现的可变数组的原理,用ArrayList实现一个容器存储对象
public class ArrayList {
Object[] objects = new Object[10];
// 定义计数器,用于计算数组中的元素个数
int index = 0; public void add(Object o) {
// 当数组满时,则创建一个新的数组,将原数组中的元素复制进新数组中,再将新的元素加入到数组中
if (index == objects.length) {
// 按原数组的2倍长度创建新数组,其实这样不太合理
Object[] newObjects = new Object[objects.length * 2];
// 将原数组中的元素复制进新数组中,再将新的元素加入到数组中
System.arraycopy(objects, 0, newObjects, 0, objects.length);
// 数组引用指向新的数组
objects = newObjects;
} // 将新增元素放到数组中
objects[index] = o;
index++;
} // 定义size函数获取元素个数
public int size() {
return index;
}
}

  用LinkedList模拟数组

package iterater.patten.design;

//探索LinkedList实现的可变数组的原理,用LinkedList实现一个容器存储对象
public class LinkedList { //定义链表的头指针head以及尾指针tail
Node head = null;
Node tail = null;
int size = 0; //添加元素
public void add(Object o) {
//一个新的结点
Node n = new Node(o, null);
//当链表为空时,head指向新添加的结点,tail也指向该结点
if (head == null) {
head = n;
tail = n;
}
//链表不为空时,tail包含的下一个结点的引用指向这个新加入的结点 tail.setNext(n);
tail = n;
size++;
} public int size() {
return size;
}
}

  Node结点的类定义 

package iterater.patten.design;

//定义一个类来存储链表中的结点
public class Node { private Object data;
private Node next;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public Node(Object data, Node next) {
super();
this.data = data;
this.next = next;
} }

  添加的元素对象所属的类的类定义

package iterater.patten.design;

public class Cat {

    private int id;

    public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public Cat(int id) {
super();
this.id = id;
}
}

  测试类 

package iterater.patten.design;

import iterater.patten.design.*;

public class IteratorTest {

    /**
* @param args
*/
public static void main(String[] args) { // ArrayList al=new ArrayList();
LinkedList al = new LinkedList();
for (int j = 0; j < 15; j++) {
al.add(new Cat(j));
}
System.out.println(al.size());
} }

  输出结果:15

【温情提示】:我们在测试类中为了提高容器的可替换性,可以定义一个接口Collection,定义add、size方法,只要保证容器类实现该接口,当用户使用add添加元素或者使用size获取元素个数的时候就可以更加方便(因为如果ArrayList中的添加元素方法叫add,而LinkedList中添加元素的方法叫addall,用户在使用的时候就会造成困扰,使用定义接口的方式,我们只对接口进行编程使用,不用去关心具体的实现内容。

  代码实现:

 public interface Collection {

     public Object add(Object o);
public int size();
}

  ArrayList和LinkedList实现该接口,并覆盖抽象方法即可,测试类中可以这样使用两个方法:

  Collection c=new ArrayList();

  c.add(object)、c.size();

  父接口引用指向子类对象,并调用子类中覆盖的方法

  但是此时又出现了一个新的问题,当我们想要对数组中的元素进行遍历时,因为不同的集合有不同的遍历方法,用ArrayList模拟的数组可以通过数组的下标索引进行遍历,但是LinkedList使用的却是另外一种方法。

针对这样的问题,解决的方法就是定义Iterator接口,里面封装了遍历数组元素的统一方式,话不多说,代码来验证。

  定义两个接口Collection和Iterator

 public interface Collection {

    Iterator iterator();
}

迭代器:

 public interface Iterator {

     public boolean hasNext();
public Object next();
}

不同的容器实现Iterator接口,获取具体的迭代器对象(即该容器类型的对象)

//具体的实现类,不同的容器,拥有不同的迭代元素的方法
private class ArrayListIterator implements Iterator{
private int currentIndex=0;
@Override
public boolean hasNext() {
if(currentIndex>=index){ return false;
}
else {
return true;
}
} @Override
public Object next() {
Object object=objects[currentIndex];
currentIndex++;
return object;
}
}

  只要ArrayList实现我前面自定义的Collection接口,覆盖iterator方法,就可以获取一个具体的实现类的对象

public class ArrayList implements Collection

   public Iterator iterator() {

         return new ArrayListIterator();

     }

  此时测试类可以这样写:

package iterater.patten.design;

import iterater.patten.design.*;

public class IteratorTest {

    /**
* @param args
*/
public static void main(String[] args) { ArrayList al = new ArrayList();
for (int j = 0; j < 15; j++) {
al.add(new Cat(j));
}
Iterator it = al.iterator();
while (it.hasNext()) {
Object object = it.next();
System.out.print(object + " ");
}
System.out.println();
} }

  迭代器Iterator的实现原理大致就是这样,尽管不同的集合内部的数据结构不同,统一了遍历集合的方式。

  最后附上ArrayList的类的代码:

package iterater.patten.design;

//探索ArrayList实现的可变数组的原理,用ArrayList实现一个容器存储对象
public class ArrayList implements Collection{
Object[] objects = new Object[10];
// 定义计数器,用于计算数组中的元素个数
int index = 0; public void add(Object o) {
// 当数组满时,则创建一个新的数组,将原数组中的元素复制进新数组中,再将新的元素加入到数组中
if (index == objects.length) {
// 按原数组的2倍长度创建新数组,其实这样不太合理
Object[] newObjects = new Object[objects.length * 2];
// 将原数组中的元素复制进新数组中,再将新的元素加入到数组中
System.arraycopy(objects, 0, newObjects, 0, objects.length);
// 数组引用指向新的数组
objects = newObjects;
} // 将新增元素放到数组中
objects[index] = o;
index++;
} // 定义size函数获取元素个数
public int size() {
return index;
}
//不同的容器,拥有不同的迭代元素的方法
private class ArrayListIterator implements Iterator{
private int currentIndex=0;
@Override
public boolean hasNext() {
if(currentIndex>=index){ return false;
}
else {
return true;
}
} @Override
public Object next() {
Object object=objects[currentIndex];
currentIndex++;
return object;
}
} @Override
public Iterator iterator() { return new ArrayListIterator();
} }

Java集合之ArrayList和LinkedList的实现原理以及Iterator详解的更多相关文章

  1. java集合(ArrayList,Vector,LinkedList,HashSet,TreeSet的功能详解)

    说起集合,我们会潜意识里想到另外一个与之相近的名词——数组,OK!两者确实有相似之处,但也正是这点才是我们应该注意的地方,下面简单列出了两者的区别(具体功能的不同学习这篇文章后就会明白了): 数组 长 ...

  2. Java集合(六)--ArrayList、LinkedList和Vector对比

    在前两篇博客,学习了ArrayList和LinkedList的源码,地址在这: Java集合(五)--LinkedList源码解读 Java集合(四)--基于JDK1.8的ArrayList源码解读 ...

  3. Java 集合 JDK1.7的LinkedList

    Java 集合 JDK1.7的LinkedList @author ixenos LinkedList LinkedList是List接口的双向链表实现,JDK1.7以前是双向循环链表,以后是双向非循 ...

  4. 从源码看Java集合之ArrayList

    Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...

  5. 转:深入Java集合学习系列:HashSet的实现原理

    0.参考文献 深入Java集合学习系列:HashSet的实现原理 1.HashSet概述: HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特 ...

  6. [转载]Java迭代器(iterator详解以及和for循环的区别)

    Java迭代器(iterator详解以及和for循环的区别) 觉得有用的话,欢迎一起讨论相互学习~[Follow] 转载自 https://blog.csdn.net/Jae_Wang/article ...

  7. java 流操作对文件的分割和合并的实例详解_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 java 流操作对文件的分割和合并的实例详解 学习文件的输入输出流,自己做一个小的示例,对文件进行分割和合并. 下面是代 ...

  8. Java 8新特性探究(八)精简的JRE详解

    http://www.importnew.com/14926.html     首页 所有文章 资讯 Web 架构 基础技术 书籍 教程 Java小组 工具资源 - 导航条 - 首页 所有文章 资讯 ...

  9. “全栈2019”Java多线程第三十章:尝试获取锁tryLock()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

随机推荐

  1. 设置MySQL主从同步

    1. 配置主服务器 1.1 编辑my.cnf文件,配置主服务器ID. [mysqld] log-bin=mysql-bin server-id=1relay-log = relay-bin relay ...

  2. struts2的@Result annotation 如何添加params

    参考: http://struts.apache.org/2.0.11/docs/result-annotation.html http://jdkcn.com/entry/add-params-to ...

  3. UVa 11400 Lighting System Design【DP】

    题意:给出n种灯泡,分别给出它们的电压v,电源费用k,每个灯泡的费用c,和所需灯泡的数量l,问最优方案的费用 看的紫书= = 首先是dp[i]为灯泡1到i的最小费用, dp[i]=min(dp[i], ...

  4. android-async-http

    安装 http://blog.csdn.net/wangwei_cq/article/details/9453345 包内的一些基本的参数 http://www.cnblogs.com/manuose ...

  5. GitHub开源库排名一百的简单介绍,值得收藏!

    GitHub Android Libraries Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitHub ...

  6. HDU 5379 Mahjong tree

    题意:在一棵有n个节点的树上放编号从1到n的麻将,要求每个点的儿子节点之间的编号连续,每棵子树内的编号连续. 解法:手推一组样例之后就可以得到如下结论然后从根节点一边讨论一边搜就好了. 当一个节点只有 ...

  7. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  8. 1045 整数礼物 c语言

    描述 Na 给准备送给ZZ两个整数,a, b,他还计算了这两个整数的平均值c,碰巧c也是整数. 但是Na 突然把b给弄丢了,你要帮助Na通过a, c计算出来b的值. 输入 输入为一行,两个用空格隔开的 ...

  9. java web 学习十六(JSP指令)

    一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: pa ...

  10. 转载:fstream和ifstream详细用法

    文件 I/O 在C++中比烤蛋糕简单多了.在这篇文章里,我会详细解释ASCII和二进制文件的输入输出的每个细节,值得注意的是,所有这些都是用C++完成的. 一.ASCII 输出 为了使用下面的方法, ...