深入理解Java中的ArrayList和LinkedList
作者:网络转载 发布时间:[ 2016/5/18 10:35:28 ] 推荐标签:测试开发技术 Java
现在来写一个测试类来看看我们自己写的集合好不好用:
package com.wang.list;
import java.util.Iterator;
public class TestMyArrayList {
public static void main(String[] args) {
MyArrayList<String> list=new MyArrayList<>();
list.add("hello");
list.add("world");
list.add("I");
list.add("am");
list.add("a");
list.add("list");
System.out.println("List的元素个数为:"+list.size());
System.out.println("list的第二个元素个数为:"+list.get(1));
//将第5个元素"a",替换为"the".
list.set(4, "the");
System.out.println("替换后的第五个元素为:"+list.get(4));
//使用iterator方式遍历List
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
打印结果:
List的元素个数为:6
list的第二个元素个数为:world
替换后的第五个元素为:the
hello
world
I
am
the
list
实现LinkedList
LinkedList是一个双链表的结构,在设计这个这个表结构时,我们需要考虑提供3个类.
1.MyLinkedList类本身.
2.Node类,该类作为静态的内部类出现,包含一个节点上的数据,以及到前一个节点和后一个节点的链.
3.LinkedListIterator类,也是一个私有类,实现Iterator接口,提供next().hannext().remove()方法.
MyLinkedList:
package com.wang.list;
import java.util.Iterator;
public class MyLinkedList<T> implements Iterable<T> {
//保存元素个数
private int theSize;
//记录修改的次数,
//用处是:用于在迭代器遍历时,用于判断在迭代过程中是否发生了修改操作,如果发生了修改,则抛出异常
private int modCount=0;
//定义两个节点,首节点和尾节点
private Node<T> begin;
private Node<T> end;
public MyLinkedList(){
clear();
}
//初始化一个空表
public void clear(){
begin=new Node<T>(null, null, null);
end=new Node<T>(null, begin, null);
begin.next=end;
theSize=0;
modCount++;
}
public int size(){
return theSize;
}
public boolean isEmpty(){
return size()==0;
}
public boolean add(T value){
add(size(),value);
return true;
}
public void add(int index,T value){
//在指定索引位置先找到那个索引处的节点类信息即先getNode(index).然后执行addBefore方法
addBefore(getNode(index),value);
}
//在指定的那个节点P的前方插入值为value的一个元素
private void addBefore(Node<T> p,T value){
Node<T> newNode=new Node<T>(value, p.prev, p);
newNode.prev.next=newNode;
p.prev=newNode;
theSize++;
modCount++;
}
//通过索引值返回对应位置的节点类信息
private Node<T> getNode(int index){
Node<T> p;
if(index<0||index>size()){
throw new IndexOutOfBoundsException();
}
if(index<(size()/2)){
p=begin.next;
for(int i=0;i<index;i++){
p=p.next;
}
}else{
p=end;
for(int i=size();i>index;i--){
p=p.prev;
}
}
return p;
}
//返回指定索引处的元素值
public T get(int index){
return getNode(index).data;
}
//将指定所引处的元素值修改为value
public T set(int index,T value){
Node<T> p=getNode(index);
T oldData=p.data;
p.data=value;
return oldData;
}
//移除指定索引处的元素值
public T remove(int index){
return remove(getNode(index));
}
private T remove(Node<T> p){
p.next.prev=p.prev;
p.prev.next=p.next;
theSize--;
modCount++;
return p.data;
}
@Override
public Iterator<T> iterator() {
return new LinkedListIteraor();
}
private class LinkedListIteraor implements Iterator<T>{
//保留第一个起始位置的节点
private Node<T> current=begin.next;
//记录此刻集合修改的总次数,之后会拿modCount再和此值作比较,如果不相等,说明在迭代过程中,
//集合发生了修改操作,则会抛出异常
private int exceptedModCount=modCount;
//判断是否可以向后移动指针
private boolean canMove=false;
@Override
public boolean hasNext() {
return current!=end;
}
@Override
public T next() {
if(exceptedModCount!=modCount){
throw new java.util.ConcurrentModificationException();
}
if(!hasNext()){
throw new java.util.NoSuchElementException();
}
T nextValue=current.data;
current=current.next;
canMove=true;
return nextValue;
}
@Override
public void remove() {
if(exceptedModCount!=modCount){
throw new java.util.ConcurrentModificationException();
}
if(!canMove){
throw new IllegalStateException();
}
MyLinkedList.this.remove(current.prev);
canMove=false;
exceptedModCount++;
}
}
private static class Node<T> {
//当前节点数据
public T data;
//到前一个节点的链
public Node<T> prev;
//到后一个节点的链
public Node<T> next;
public Node(T data, Node<T> prev, Node<T> next) {
this.data = data;
this.prev = prev;
this.next = next;
}
}
}
测试类TestMyLinkedList:
package com.wang.list;
import java.util.Iterator;
public class TestMyLinkedList {
public static void main(String[] args) {
MyLinkedList<Integer> list=new MyLinkedList<>();
list.add(1);
list.add(5);
list.add(7);
list.add(6);
list.add(4);
list.add(2);
list.add(3);
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+" ");
}
System.out.println();
list.set(2, 8);
list.remove(0);
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
}
打印结果:
1 5 7 6 4 2 3
5 8 6 4 2 3
遍历集合时进行修改操作为什么会抛出ConcurrentModificationException:
以前,我碰到过这样的问题,需要删除某一个元素,首先要在先遍历找到要删除的元素,然后删除它,结果会抛出一个ConcurrentModificationException()异常,错误代码大概是这样(以上面的测试类中LinkList为例):
for(Integer i:list){
if(i==6){
list.remove(6);
}
}
注意:我上面并没有实现这个remove()方法,这个remove()是根据传入的值进行删除,而我只写了一个根据传入的索引位置来删除元素的方法.这里假设我们使用的java提供的LinkedList.
现在我们知道了原因,因为增强的for循环内部使用的是iterator迭代器的方式进行遍历的,在遍历过程中,如果进行修改操作会导致exceptedModCount的值和modCount的值不相等.因此会抛出ConcurrentModificationException的异常.
正确的删除元素的方式应该是使用iterator()的方式遍历并进行删除操作,因为迭代器中的remove()方法和集合中的remove()有一点不同是,前者删除后,会进行exceptedModCount++,因为不会抛出上面那个异常:
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
if(it.next()==6){
it.remove();
}
}
注:实现这两个集合的代码参考了JAVA语言描述的<数据结构和算法>一书,我自己实现了一个比较丑陋的版本,不够精致,不敢献丑,看着参考书上又修改了一番,不喜勿喷>..<
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Java性能测试有哪些不为众人所知的原则?Java设计模式??装饰者模式谈谈Java中遍历Map的几种方法Java Web入门必知你需要理解的Java反射机制知识总结编写更好的Java单元测试的7个技巧编程常用的几种时间戳转换(java .net 数据库)适合Java开发者学习的Python入门教程Java webdriver如何获取浏览器新窗口中的元素?Java重写与重载(区别与用途)Java变量的分类与初始化JavaScript有这几种测试分类Java有哪四个核心技术?给 Java开发者的10个大数据工具和框架Java中几个常用设计模式汇总java生态圈常用技术框架、开源中间件,系统架构及经典案例等

sales@spasvo.com