Java集合之ArrayList和LinkedList的实现原理以及Iterator详解

ArrayList实现可变数组的原理:

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

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

用ArrayList模拟数组:

 1 package iterater.patten.design;
 2 
 3 //探索ArrayList实现的可变数组的原理,用ArrayList实现一个容器存储对象
 4 public class ArrayList {
 5     Object[] objects = new Object[10];
 6     // 定义计数器,用于计算数组中的元素个数
 7     int index = 0;
 8 
 9     public void add(Object o) {
10         // 当数组满时,则创建一个新的数组,将原数组中的元素复制进新数组中,再将新的元素加入到数组中
11         if (index == objects.length) {
12             // 按原数组的2倍长度创建新数组,其实这样不太合理
13             Object[] newObjects = new Object[objects.length * 2];
14             // 将原数组中的元素复制进新数组中,再将新的元素加入到数组中
15             System.arraycopy(objects, 0, newObjects, 0, objects.length);
16             // 数组引用指向新的数组
17             objects = newObjects;
18         }
19 
20         // 将新增元素放到数组中
21         objects[index] = o;
22         index++;
23     }
24 
25     // 定义size函数获取元素个数
26     public int size() {
27         return index;
28     }
29 }

  用LinkedList模拟数组

 1 package iterater.patten.design;
 2 
 3 //探索LinkedList实现的可变数组的原理,用LinkedList实现一个容器存储对象
 4 public class LinkedList {
 5 
 6     //定义链表的头指针head以及尾指针tail
 7     Node head = null;
 8     Node tail = null;
 9     int size = 0;
10 
11     //添加元素
12     public void add(Object o) {
13         //一个新的结点
14         Node n = new Node(o, null);
15         //当链表为空时,head指向新添加的结点,tail也指向该结点
16         if (head == null) {
17             head = n;
18             tail = n;
19         }
20         //链表不为空时,tail包含的下一个结点的引用指向这个新加入的结点
21         
22         tail.setNext(n);
23         tail = n;
24         size++;
25     }
26 
27     public int size() {
28         return size;
29     }
30 }

  Node结点的类定义 

 1 package iterater.patten.design;
 2 
 3 //定义一个类来存储链表中的结点
 4 public class Node {
 5 
 6     private Object data;
 7     private Node next;
 8     public Object getData() {
 9         return data;
10     }
11     public void setData(Object data) {
12         this.data = data;
13     }
14     public Node getNext() {
15         return next;
16     }
17     public void setNext(Node next) {
18         this.next = next;
19     }
20     public Node(Object data, Node next) {
21         super();
22         this.data = data;
23         this.next = next;
24     }
25     
26 }

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

 1 package iterater.patten.design;
 2 
 3 public class Cat {
 4 
 5     private int id;
 6 
 7     public int getId() {
 8         return id;
 9     }
10 
11     public void setId(int id) {
12         this.id = id;
13     }
14 
15     public Cat(int id) {
16         super();
17         this.id = id;
18     }
19 }

  测试类 

 1 package iterater.patten.design;
 2 
 3 import iterater.patten.design.*;
 4 
 5 public class IteratorTest {
 6 
 7     /**
 8      * @param args
 9      */
10     public static void main(String[] args) {
11 
12         // ArrayList al=new ArrayList();
13         LinkedList al = new LinkedList();
14         for (int j = 0; j < 15; j++) {
15             al.add(new Cat(j));
16         }
17         System.out.println(al.size());
18     }
19 
20 }

  输出结果:15

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

  代码实现:

1 public interface Collection {
2 
3     public Object add(Object o);
4     public int size();
5 }

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

  Collection c=new ArrayList();

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

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

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

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

  定义两个接口Collection和Iterator

1 public interface Collection {
2 
3     Iterator iterator();
4 }

 

1 public interface Iterator {
2 
3     public boolean hasNext();
4     public Object next();
5 }

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

 1     //具体的实现类,不同的容器,拥有不同的迭代元素的方法
 2     private class ArrayListIterator implements Iterator{
 3         private int currentIndex=0;
 4         @Override
 5         public boolean hasNext() {
 6             if(currentIndex>=index){
 7                 
 8                 return false;
 9             }
10             else {
11                 return true;
12             }
13         }
14 
15         @Override
16         public Object next() {
17             Object object=objects[currentIndex];
18             currentIndex++;
19             return object;
20         }
21     }

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

      public class ArrayList implements Collection

1 public Iterator iterator() {
2         
3         return new ArrayListIterator();
4     }

  此时测试类可以这样写

 1 package iterater.patten.design;
 2 
 3 import iterater.patten.design.*;
 4 
 5 public class IteratorTest {
 6 
 7     /**
 8      * @param args
 9      */
10     public static void main(String[] args) {
11 
12         ArrayList al = new ArrayList();
13         for (int j = 0; j < 15; j++) {
14             al.add(new Cat(j));
15         }
16         Iterator it = al.iterator();
17         while (it.hasNext()) {
18             Object object = it.next();
19             System.out.print(object + " ");
20         }
21         System.out.println();
22     }
23 
24 }

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

  最后附上ArrayList的类的代码:

 1 package iterater.patten.design;
 2 
 3 
 4 //探索ArrayList实现的可变数组的原理,用ArrayList实现一个容器存储对象
 5 public class ArrayList implements Collection{
 6     Object[] objects = new Object[10];
 7     // 定义计数器,用于计算数组中的元素个数
 8     int index = 0;
 9 
10     public void add(Object o) {
11         // 当数组满时,则创建一个新的数组,将原数组中的元素复制进新数组中,再将新的元素加入到数组中
12         if (index == objects.length) {
13             // 按原数组的2倍长度创建新数组,其实这样不太合理
14             Object[] newObjects = new Object[objects.length * 2];
15             // 将原数组中的元素复制进新数组中,再将新的元素加入到数组中
16             System.arraycopy(objects, 0, newObjects, 0, objects.length);
17             // 数组引用指向新的数组
18             objects = newObjects;
19         }
20 
21         // 将新增元素放到数组中
22         objects[index] = o;
23         index++;
24     }
25 
26     // 定义size函数获取元素个数
27     public int size() {
28         return index;
29     }
30     //不同的容器,拥有不同的迭代元素的方法
31     private class ArrayListIterator implements Iterator{
32         private int currentIndex=0;
33         @Override
34         public boolean hasNext() {
35             if(currentIndex>=index){
36                 
37                 return false;
38             }
39             else {
40                 return true;
41             }
42         }
43 
44         @Override
45         public Object next() {
46             Object object=objects[currentIndex];
47             currentIndex++;
48             return object;
49         }
50     }
51 
52     @Override
53     public Iterator iterator() {
54         
55         return new ArrayListIterator();
56     }
57 
58 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值