前言
本文为Java集合框架相关知识,Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
一、集合框架体系
二、List
1.数组扩容
// 扩容方法和位运算 public class Demo01 { public static void main(String[] args) { int[] arr= new int[4]; arr[0] = 10; arr[1] = 11; arr[2] = 12; arr[3] = 13; arr = grow(arr); System.out.println(arr.length); } public static int[] grow(int[] arr){ //int[] newArr = new int[arr.length+arr.length/2]; // >>1 位运算 二进制向右移一位变成原来的 一半 // 1<< 二进制向左移一位变成元的的 一倍 int[] newArr = new int[arr.length+arr.length>>1]; /** 方法一: */ for (int i = 0; i < arr.length; i++) { newArr[i] = arr[i]; } /** * 方法二: */ System.arraycopy(arr , 0 ,newArr,0,arr.length); /** * 方法三: */ newArr = Arrays.copyOf(arr, arr.length+arr.length/2); return newArr; } }
2.迭代器 : 只服务于Collection接口下的集合
Iterator
- hasNext() 如果迭代具有更多元素,则返回 true 。
- next() 返回迭代中的下一个元素。
- remove() 从底层集合中删除此迭代器返回的最后一个元素(可选操作)。
// 使用Iterator 迭代器 public static void print(ArrayList<Person> list){ Iterator<Person> iterator = list.iterator(); while (iterator.hasNext()){ Person person = iterator.next(); System.out.println(person.getName() + "\t" + person.getAge()); } }
ListIterator
void add(E e) :将指定的元素插入列表(可选操作)。
boolean hasNext():如果此列表迭代器在向前方向遍历列表时具有更多元素,则返回 true 。
boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true 。
E next() 返回列表中的下一个元素,并且前进光标位置。
int nextIndex() 返回由后续调用返回的元素的索引 next() 。
E previous()返回列表中的上一个元素,并向后移动光标位置。
int previousIndex() 返回由后续调用返回的元素的索引 previous()。
void remove() 从列表中删除 next()或 previous() (可选操作)返回的最后一个元素。
void set(E e) 用指定的元素(可选操作)替换 next()或 previous()返回的最后一个元素。
public static void itRepeat(ArrayList<Person> list){ System.out.println("去除重复元素:"); // 使用ListIterator 接口可以实现从指定位置迭代集合 ListIterator<Person> iterator; for (int i = 0; i < list.size() ; i++) { iterator = list.listIterator(i+1); while (iterator.hasNext()){ Person person = iterator.next(); if (list.get(i).equals(person)){ iterator.remove(); System.out.println("即将被删除:..."+person); } } } }
terator VS ListIterator
ListIterator有add()方法,可以向List中添加对象,而Iterator没有
ListIterator和Iterator都有hasNext() 和 next() 方法,但ListIterator可以实现指定位置遍历,并且可以顺序遍历和逆序遍历。
ListIterator有set方法,可以在遍历中修改对象。
3.ArrayList
有序可重复 ,底层是动态数组实现 —— 线程不安全
添加数据,如果是基本数据类型会自动装箱为包装类,第一次添加数组长度为10
存储的数据超过数组长度,会自动进行数组扩容,扩容为原来的1.5倍
集合长度有限,最大容量默认为: Integer.MAX_VALUE-8
为什么空8位出来: 1、存储Headerwords;2、避免一些机器内存溢出,减少出错几率,所以少分配;3、最大还是能支持到Integer.MAX_VALUE(2^31 -1)
public class Test{ public static void main(String[] args) { ArrayList list = new ArrayList(); // 1、添加元素 —— 如果数据是基本数据类型会自动装箱为包装类 list.add(1); list.add("a"); list.add(true); list.add(10.1); list.add(2); // 2、删除元素 —— 根据下标删除 list.remove(1); // 根据对象删除 list.remove(new Integer(2)); // 3、修改 list.set(1,"b"); // 4、遍历集合 print(list); } public static void print(ArrayList list){ System.out.println("-------- for循环 ----------"); for (int i = 0; i < list.size() ; i++) { System.out.print(list.get(i) + "\t"); } System.out.println(); System.out.println("=========== 迭代器循环 ========="); Iterator iterator = list.iterator(); while (iterator.hasNext()){ System.out.print(iterator.next() + "\t"); } System.out.println(); } }
4.LinkedList
- 底层是 双向链表 实现 —— 线程不安全
- 第一次添加对象,把对象添加到Node节点中,falst指向第一个节点,不存在索引
- 集合长度无限
// 创建 LinkedList 对象 LinkedList list = new LinkedList(); list.add("111"); //添加一个新元素,默认尾部添加 list.add("222"); list.add("333"); list.addFirst("444"); //在头部添加一个新元素 list.addLast("555"); //在尾部添加一个新元素 Object data1=list.removeFirst(); //移除头部元素并返回值 System.out.println(data1); Object data2=list.removeLast(); //移除尾部元素并返回值 System.out.println(data2); list.getFirst(); // 获取头部元素并返回值 list.getLast(); // 获取尾部元素并返回值 for(Object object : list){ System.out.println(object); } // 其他方法的使用与 ArrayList一致
5. ArrayList和LinkedList的区别
数据结构的实现不同。 ArrayList是动态数组实现,LinkedList是双向链表实现
List item查询的效率。ArrayList有下标查询速度快,而LinkedList底层是链表结构,查询需从头开始依次往下查找
增删的效率。在排除增删前后两头的情况下,LinkedList的速度比ArrayList的快,因为LinkedList的添加和删除节点,只要其他节点的前驱后继指引值发生变化,而ArrayList增加删除会更改数组的结构
6.foreach的本质
- 使用foreach来遍历集合的话,本质上是将其转换为迭代器来使用
System.out.println("=========== foreach循环 ========="); for (Object obj:list) { System.out.print(obj+"\t"); } System.out.println(); // 等价于下边代码 System.out.println("=========== foreach循环 ========="); Iterator iterator = list.iterator(); while(iterator.hasNext()) { Object obj = iterator.next(); System.out.print(obj+"\t"); }
7.Vector
- 数组结构实现,查询快、增删慢。
- JDK1.0版本,线程安全、运行效率比ArrayList较慢。
public class TestVector { public static void main(String[] args) { //创建集合 Vector vector=new Vector<>(); //1添加元素 vector.add("草莓"); vector.add("芒果"); vector.add("西瓜"); System.out.println("元素个数:"+vector.size()); //2删除 // vector.remove(0); // vector.remove("西瓜"); // vector.clear(); //3遍历 //使用枚举器 Enumeration en=vector.elements(); while(en.hasMoreElements()) { String o=(String)en.nextElement(); System.out.println(o); } //4判断 System.out.println(vector.contains("西瓜")); System.out.println(vector.isEmpty()); //5vector其他方法 //firsetElement、lastElement、elementAt(); } }
8.Stack
- 模拟 栈 的实现 —— 底层用数组存储数据
- 特点是:先进后出
public class Demo05 { public static void main(String[] args) { Stack stack = new Stack(); // 添加元素 // Stack类的add方法与push方法区别: // add方法返回的是boolean类型的值 // push方法返回的是当前添加的元素 stack.push("a"); stack.push("b"); stack.add("c"); stack.push("d"); // 集合中的元素个数 System.out.println(stack.size()); // 弹出栈顶元素 System.out.println(stack.pop()); System.out.println(stack.pop()); } }
三、Queue
1.队列的定义
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。
队头(first):允许删除的一端,又称队首。
队尾(Rearlsat:允许插入的一端。
空队列:不包含任何元素的空表。
2.队列的使用
public class Demo01 { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.add("小明"); // 向队列添加元素,当队列满时,add方法抛出unchecked异常,而offer方法返回false。 queue.offer("小黑"); queue.offer("小蓝"); queue.offer("小而"); // 集合中的个数 System.out.println(queue.size()); // 4 // 查询头部元素:如果队列为空,element方法会抛出异常,peek方法会返回null System.out.println(queue.element()); // 小明 System.out.println(queue.peek()); // 小明 // 打印队列头 System.out.println(queue.poll()); // 小明 ,如果队列为空,remove方法会抛出异常,poll方法会返回null。 System.out.println(queue.size()); // 3 System.out.println(queue.remove()); // 小黑 } }