Java的学习记录:charpter7.集合(ArrayList和LinkedList的区别)
1.集合
1.1集合的概述
1.java集合框架
List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口。
Set接口的实现类:HashSet,LinkedHashSet,TreeSet
List接口的实现类:ArrayList,Vector,LinkedList
Map接口的实现类:Hashtable,LinkedHashMap,HashMap,TreeMap
Collection接口下还有个Queue接口,有PriorityQueue类
(来自于网络图片)
2.集合和数组的区别
(1)长度:
数组:长度固定
集合:长度可变
(2)内容:
数组:可以是基本类型,也可以是引用类型
集合:只能是引用类型
(3)元素内容
数组:只能存储同一类型的元素
集合:可以储存不同类型的元素
3.collection集合的通用方法:
1.在集合末尾添加元素 boolean add(E e) 2.若本类集合中有与o的值相等的元素,则删除该元素,并返回true boolean remove(Object o) 3.删除本类集合中的所有元素 void clear() 4.判断集合中是否包含某元素 boolean contains(Object o) 5.判断集合是否为空 boolean isEmpty() 6.返回集合中的元素个数 int size() 7.将一个类集合中的所有元素添加到另一个集合中 boolean addAll(Collection <?extends E> c) 8.返回一个包含本类集合中所有元素的数组,数组类型为Obejct[] Object[] toArray() 9.迭代器,集合的专用遍历方式 Iterator iterator()
1.2Collection集合的分类
Colletion集合接口下分为List接口和Set接口,两者继承于Collection
接口。
1.2.1List接口
List接口的特点是:元素按照进入的先后顺序保存,是有序的,并且元素可以重复。
List的特有功能:
1.在制定位置添加元素 void add(int index, E element) 2.根据指定索引删除元素,并返回该元素 E remove(int index) 3.把指定索引位置的元素替换为指定的值,返回替换前的值 E set(int index, E element) 4.返回指定元素在集合中第一次出现的索引 int indexOf(Obejct o) 5.获取指定位置的元素 E get(int index) 6.列表迭代器 ListIteraror listIterator() 7.截取集合 List subList(int fromIndex, int toIndex)
1.ArrayList:
ArrayList是List接口的一种实现类,相当于是一种动态数组,ArrayList在内存中分配连续的内存空间,它的底层数据结构是数组,数组的特点是每个元素都有自己对应的下标,因而,使用ArrayList访问元素的时候是非常方便的,但是如果进行插入或删除操作时,会存在大量挪位置和分配多余空间的操作,对计算机的性能消耗较大,因而,插入或删除元素较慢。
代码演示:
/** * @Description ArrayList 顺序表(动态数组) * @date 2020/5/27 */ public class ArrayList<T> implements List<T>{ /** * 默认初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 默认源数据扩容率 */ private static final float DEFAULT_EXPAND_RATE = 1.5F; /** * 核心源数据 */ private Object[] elementData; /** * 常量空数组 */ private final Object[] EMPTY_DATA = {}; /** * 数组拷贝的临时记录点 */ private Object[] copy = EMPTY_DATA; /** * 新元素起始位置,当前数组中元素的数量 */ private int size; public ArrayList(){ this(DEFAULT_CAPACITY); } public ArrayList(int initCapacity){ if(initCapacity==0){ elementData = EMPTY_DATA; }else if(initCapacity>0){ elementData = new Object[initCapacity]; }else{ System.err.println("初始化容量错误:initCapacity "+initCapacity); } } private void ensureCapacity(int needCapacity){ int expandCapacity = needExpand(needCapacity); if(expandCapacity<=0){ return; } final int newCapacity = (int)Math.ceil((elementData.length+expandCapacity)*DEFAULT_EXPAND_RATE); copy = elementData; elementData = new Object[newCapacity]; System.arraycopy(copy,0,elementData,0,size); copy = EMPTY_DATA; } private int needExpand(int needCapacity){ return needCapacity - (elementData.length-size); } @Override public int size() { return size; } @Override public boolean isEmpty() { return size==0; } @Override public Object[] toArray() { return Arrays.copyOf(elementData,size); } @Override public int indexOf(T t) { for (int i = 0; i < size; i++) { if(elementData[i].equals(t)){ return i; } } return -1; } @Override public int lastIndexOf(T t) { for (int i = size-1; i >= 0; i--) { if(elementData[i].equals(t)){ return i; } } return -1; } @Override public boolean contains(T t) { return -1 != indexOf(t); } @Override public void add(T t) { ensureCapacity(1); elementData[size++] = t; } @Override public void add(T[] arr) { ensureCapacity(arr.length); System.arraycopy(arr,0,elementData,size,arr.length); size += arr.length; } @Override public void add(List<T> list) { add((T[])list.toArray()); } @Override public T remove(int index) { if(index<0 || index>=size){ throw new ArrayIndexOutOfBoundsException("index out of bounds : "+index); } T t = (T)elementData[index]; for (int i = index; i <size-1 ; i++) { elementData[i] = elementData[i+1]; } elementData[--size] = null; return t; } @Override public boolean remove(T t) { int index = indexOf(t); if(-1==index){ return false; } remove(index); return true; } @Override public T get(int index) { if(index<0 || index>=size){ throw new ArrayIndexOutOfBoundsException("index out of bounds : "+index); } return (T)elementData[index]; } @Override public void sort(boolean ascend, Comparator<T> comparator) { if(null==elementData || elementData.length<=1) return; if(null==comparator) throw new NullPointerException("comparator null pointer exception"); Arrays.sort((T[])elementData,0,size-1,comparator,ascend); } //匿名内部类 :接口和抽象类不能直接实例化,但是可以通过匿名内部类实例化 @Override public Iterator<T> iterator() { return new Iterator<T>() { private int index = -1; @Override public boolean hasNext() { return ++index<size; } @Override public T next() { return (T)elementData[index]; } @Override public T remove() { T t = next(); ArrayList.this.remove(index); index--; return t; } }; } }
2.LinkedList:
LinkedList:是List接口的一种实现类,本质上是一种链表的形式,根据链表的形式不同又分为单链表和双链表,LinkedList分配的空间是不连续的,不具备数组有下标的特征,因而,在访问元素的时候性能较慢,但是因为链表中的每个节点都是独立的关系,因而在执行插入或删除操作的时候较快,无序分配多余的空间,需要多少节点就分配多少空间,性能较高。
LinkedList的特有功能:
添加: addFirst() addLast() 删除: removeFirst() removeLast() 获取: getFirst() getLast()
代码演示:(双向链表)
/** * @Description //双向链表 * @date 2020/6/2 */ public class LinkedList<T> implements List<T> { /** * 隐藏在内部的节点:内部类 * @param <T> */ //匿名内部类,节点类 private class Node<T> { //节点类型的类 Node<T> prev; //节点的上一个引用 T t; //节点值的引用 Node<T> next;//节点的下一个引用 //既没有前节点,又没有后节点 public Node(T t) { this(null,t,null); } //有前节点,没有后节点 public Node(Node<T> prev, T t) { this(prev, t, null); } //有后节点,但是没有前节点 public Node(T t, Node<T> next) { this(null,t,next); } //既有前节点,又有后节点 public Node(Node<T> prev, T t, Node<T> next) { this.prev = prev; this.t = t; this.next = next; } } /** * 根节点 */ private Node<T> root; /** * 当前节点 */ private Node<T> curr; /** * 当前集合中元素的数量 */ private int size; public LinkedList() { } public LinkedList(T t) { add(t); } @Override public int size() { return size; } @Override public boolean isEmpty() { return size == 0; } @Override public Object[] toArray() { Object[] objs = new Object[size]; Iterator<T> it = iterator(); int count = 0; while(it.hasNext()){ objs[count++] = it.next(); } return objs; } @Override public int indexOf(T t) { Iterator<T> it = _iterator(true); int count = -1; while(it.hasNext()){ count++; if(it.next().equals(t)){ return count; } } return -1; } @Override public int lastIndexOf(T t) { Iterator<T> it = _iterator(false); int count = size; while(it.hasNext()){ count--; if(it.next().equals(t)){ return count; } } return -1; } @Override public boolean contains(T t) { return -1 != indexOf(t); } @Override //向链表中添加元素 public void add(T t) { if (size == 0) { //判空,链表中没有添加元素 root = new Node<>(t); curr = root; //链表中没有添加元素,后一个即当前添加的元素curr就是根节点root本身 } else { //双向链表 Node<T> temp = new Node<>(curr, t); //将新增节点temp的前置引用指向curr的内容t curr.next = temp; //将curr的后置引用指向新添加的节点temp curr = temp; //现在temp就是原来的curr } size++; } @Override //向链表中添加数组(即逐个添加元素) public void add(T[] arr) { if (null == arr) return; //判空 for (T t : arr) { add(t); //调用添加元素的方法 } } @Override //向链表中添加集合(即逐个添加数组) public void add(List<T> list) { if (null == list) return; add((T[]) list.toArray()); //强转,调用添加数组的方法 } private Iterator<T> getByIndex(int index){ if(index<0 || index>=size){ throw new ArrayIndexOutOfBoundsException("index out of bounds:"+index); } Iterator<T> it = _iterator(true); while(it.hasNext()){ if (index-- == 0){ return it; } } return null; } @Override public T remove(int index) { return getByIndex(index).remove(); } @Override public boolean remove(T t) { boolean removed = false; Iterator<T> it = _iterator(true); while(it.hasNext()){ if (it.next().equals(t)){ it.remove(); if(!removed){ removed = true; } } } return removed; } @Override public T get(int index) { return getByIndex(index).next(); } @Override public void sort(boolean ascend, Comparator<T> comparator) { } private Iterator<T> _iterator(boolean forward){ return new Iterator<T>() { private Node<T> temp; private boolean first = true; @Override public boolean hasNext() { temp = first ? (forward ? root : curr):(forward ? temp.next : temp.prev); if (first){ first = false; } return null != temp; } @Override public T next() { return temp.t; } @Override public T remove(){ T t = temp.t; Node<T> prev = temp.prev; Node<T> next = temp.next; if(null !=prev){ prev.next = next; temp.prev = null; }else{ //如果删除的是第一个 root = next; if(forward) { first = true; } } if (null != next){ next.prev = prev; temp.next = null; }else { //如果删除的是最后一个 curr = prev; if (!forward) { first = true; } } if(!first){ temp = forward ? prev : next; } size--; return t; } }; } @Override public Iterator iterator() { return _iterator(true); } }
3.Vector
Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
总结:
1.ArrayList底层数据结构是数组,查询快,增删慢;LinkedList底层结构是链表,查询慢,增删快
2.ArrayList最常用,线程不安全,在查询时效率高;LinkedList线程不安全,但是在增删时,效率高
3.综上所述,在不考虑线程安全的前提下,需要随机快速访问元素时使用ArrayList;插入、删除操作较多时使用LinkedList。
1.2.1Set接口
Set接口的特点是:元素是无序的,仅接受一次该元素,元素不可重复,是唯一的,并做内部排序
- Java集合:List、Set和Map的区别,ArrayList和LinkedList有何区别..........
- java学习(4)ArrayList、LinkedList类以及区别
- java集合学习(四)---线程安全版的ArrayList和LinkedList
- 零基础学习java日记第十三天 内部类 集合 ArrayList LinkedList HashMap哈希表
- (9) java ---- 集合框架图 ArrayList,LinkedList,Vector各自的性能特点及区别
- 一、基础篇--1.2Java集合-Arraylist 与 LinkedList 区别
- 一、基础篇--1.2Java集合-Arraylist 与 LinkedList 区别
- Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及区别
- Java学习——List的使用方法以及ArrayList和LinkedList的区别
- java基础(集合List-ArrayList、LinkedList、Vector的区别)
- Java集合:List、Set和Map的区别,ArrayList和LinkedList有何区别..........
- java 集合学习笔记2-ArrayList LinkedList Vector 泛型 增强for 可变参数
- 你知道java集合ArrayList和LinkedList的区别吗?
- JAVA学习第三十五课(常用对象API)—Vector、LinkedList、ArrayList集合演示
- Java 集合深入学习--ArrayList,LinkedList和Vector
- java 集合 之 链表和线性表以及ArrayList的各方法的介绍及示例 及 ArrayList与LinkedList的区别分析 及 ArrayList与Array(数组)的区别
- JAVA学习---集合系列---ArrayList、Vector和LinkedList等的差别
- 关于java集合(3)-ArrayList和LinkedList的区别
- java集合学习之:ArrayList和LinkedList
- Java基础之集合类如ArrayList、LinkedList、HashMap、HashTable的区别