本文主要是介绍集合框架 Collection - List(Arrays.asList)- 迭代器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Arrays.asList()
关于:Collection coll1 = Arrays.asList(123, 4567);1、
Arrays.asList()方法属于"Arrays类",返回的是一个"java.util.Arrays.ArrayList"(这是一个 AbstractList的私有静态内部类,不是"java.util.ArrayList")
所以,使用 Arrays.asList(123, 4567) 时,需要导入 "import java.util.Arrays"Arrays.asList(),返回的是AbstractList的一个实例,这里发生了向上转型,即一个更具体的类(AbstractList)的实例被赋值给了一个更一般的接口(Collection)类型的变量。2、
Arrays.asList(123, 4567),详解如下:将一组元素,转换为,一个固定大小的列表(List)的静态方法,需要注意的是,返回的列表(List)大小是固定的,不能添加或删除元素,如果,你尝试添加、删除,将会抛出"UnsupportedOperationException"。另,如果你需要一个可以修改的列表,应该使用 new ArrayList<>(Arrays.asList(123, 4567)) 来创建一个新的 ArrayList 实例,这样就可以修改它的内容了。3、代码示例import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.List; public static void main(String[] args) {// 创建一个不可修改的固定大小列表List<Integer> fixedList = Arrays.asList(123, 4567);// 使用固定大小列表创建一个可修改的ArrayListList<Integer> modifiableList = new ArrayList<>(fixedList);System.out.println("Fixed List= " + fixedList); // Fixed List= [123, 4567]System.out.println("Modifiable List= " + modifiableList); // Modifiable List= [123, 4567]// 向可修改的ArrayList中添加一个新元素modifiableList.add(8910);System.out.println("Modifiable= " + modifiableList); // Modifiable= [123, 4567, 8910]// 尝试向固定大小的列表添加元素,这将抛出 UnsupportedOperationException 的异常fixedList.add(9876); // Exception in thread "main" java.lang.UnsupportedOperationException}
17、集合框架
1、"集合的概述":集合、数组都是对多个数据进行存储操作的结构,简称Java容器。java集合类,可以用与存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。2、集合可分为"Collection" 和 "Map"两种体系,如下,a、Collection接口:单例数据,用来存随一个一个的对象,定义了存取一组对象的方法集合List:元素有序,可重复的集合Set:元素无序,不可重复的集合b、Map接口,双列数据,用来存随一对一对的,保存具有映射关系"key-value对"的集合
Collection接口
Collection接口:集合框架的顶级接口,所有接口都是从"Collection接口"继承过来的,是"Set 和 List的父接口",但"不是Map的父接口"。
常用方法-1
1、add(Object e):将元素e添加到集合中2、size():获取添加元素的个数3、addAll(Collection coll):将coll集合中的元素添加到当前的集合中4、clear():清空集合元素5、isEmpty():判断当前集合是否为空import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;public static void main(String[] args) {Collection coll = new ArrayList();// add(Object e):将元素e添加到集合中coll.add("AA");coll.add("BB");coll.add(123); // 自动装箱coll.add(new Date());System.out.println("coll= " + coll); // [AA, BB, 123, Wed Feb 28 15:15:51 CST 2024]// size():获取添加元素的个数System.out.println(coll.size()); // 4Collection coll2 = new ArrayList();coll2.add(456);coll2.add("CC");System.out.println("coll2= " + coll2); // coll2= [456, CC]// addAll(Collection coll):将coll集合中的元素添加到当前的集合中coll.addAll(coll2);System.out.println("coll= " + coll); // coll= [AA, BB, 123, Wed Feb 28 15:17:44 CST 2024, 456, CC]System.out.println(coll.isEmpty()); // false// clear():清空集合元素coll.clear();System.out.println("coll= " + coll); // []// isEmpty():判断当前集合是否为空System.out.println(coll.isEmpty()); // true
}
常用方法-2
1、contains(Object obj):判断当前集合中是否包含obj2、containsAll(Collection coll):判断形参coll中的所有元素,是否都存在于当前集合中3、remove(Object obj):从当前集合中移除obj元素4、removeAll(Collection coll):差集,从当前集合中移除coll中所有的元素5、retainAll(Collection coll):交集,获取当前集合和coll集合的交集,并返回给当前集合6、equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同7、hashCode():返回当前对象的哈希值8、集合 —> 数组:toArray()"注意":向Collection接口的实现类的对象中,添加数据obj时,要求obj所在类要重写equals()
public static void main(String[] args) {Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(789);coll.add(new String("Tom"));System.out.println(coll); // [123, 456, 789, Tom]// ---------- contains(Object obj):判断当前集合中是否包含obj ----------// 我们在判断时,会调用obj对象所在类的equals()boolean contains1 = coll.contains(123);boolean contains2 = coll.contains(1234);System.out.println(contains1); // trueSystem.out.println(contains2); // false// ---------- containsAll(Collection coll):判断形参coll中的所有元素是否都存在于当前集合中 ----------Collection coll2 = Arrays.asList(123,456);System.out.println(coll.containsAll(coll2)); // trueCollection coll3 = Arrays.asList(123,4567);System.out.println(coll.containsAll(coll3)); // false// ---------- remove(Object obj):从当前集合中移除obj元素 ----------coll.remove(123);System.out.println(coll); // [456, 789, Tom]// ---------- removeAll(Collection coll):差集,从当前集合中移除coll中所有的元素 ----------Collection coll1 = Arrays.asList(123,456);coll.removeAll(coll1);System.out.println(coll); // [789, Tom]
}
public static void main(String[] args) {Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(789);coll.add(new String("Tom"));System.out.println(coll); // [123, 456, 789, Tom]// ---------- retainAll(Collection coll):交集,获取当前集合和coll集合的交集,并返回给当前集合 ----------Collection coll2 = Arrays.asList(123,456,789);coll.retainAll(coll2);System.out.println(coll); // [123, 456, 789]// ---------- equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同 ----------System.out.println(coll.equals(coll2)); // truecoll.add(000);System.out.println(coll.equals(coll2)); // false
}
public static void main(String[] args) {Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(789);coll.add(new String("Tom"));System.out.println(coll); // [123, 456, 789, Tom]// ---------- hashCode():返回当前对象的哈希值 ----------System.out.println(coll.hashCode()); // 5134763// ---------- 集合 —> 数组:toArray() ----------Object[] arr = coll.toArray();System.out.println(Arrays.toString(arr)); // [123, 456, 789, Tom]for (int i = 0; i < arr.length; i++) {if(i != arr.length-1){System.out.print(arr[i] + "-");} else {System.out.print(arr[i]);}}// 这个for循环,最终打印的是:123-456-789-Tom// ---------- 拓展:数组 -> 集合:调用Arrays类的静态方法asList() ----------List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});System.out.println(list); // [AA, BB, CC]List arr1 = Arrays.asList(new int[]{123, 456});System.out.println(arr1.size()); // 1List arr2 = Arrays.asList(new Integer[]{123, 456});System.out.println(arr2.size()); // 2
}
迭代器接口
GOP给迭代器模式定义为:提供一种方法,访问容器对象中各个元素,而又不需暴露该对象内部细节,迭代器模式,就是为容器而生用于遍历Collection集合中的元素,"Collection接口继承了java.long.Iterable接口",该接口有一个 iterator()方法,那么,所有实现了Collection接口的集合类,都有一个 iterator()方法。
/* 集合元素的遍历操作,使用迭代器Iterator接口,1、集合对象(Collection对象),每次调用 iterator() 方法,都得到一个全新的迭代器对象2、hasNext() 和 next() 方法hasNext()方法,用于检查集合中是否还有下一个元素。如果,迭代器指向的集合中还有元素,则此方法返回 true;否则返回 false。next()方法,用于返回迭代器指向的下一个元素,并将迭代器向前移动一位。如果,迭代器已经指向集合的末尾(即没有下一个元素),则调用此方法会抛出 NoSuchElementException。3、默认游标,都在集合的第一个元素之前:当你首次获取一个迭代器时,它的“游标”或“位置”,位于集合的第一个元素之前,调用 next() 方法,会使游标移动到第一个元素,随后的 next() 调用,会继续移动游标到下一个元素。4、内部定义了 remove() 方法Iterator接口中的remove()方法,允许,在迭代过程中,安全地删除集合中的当前元素(即上一个被 next() 方法返回的元素),这是 Iterator 特有的,不同于集合直接调用 remove() 方法,因为集合的 remove() 方法需要知道要删除的确切元素。在迭代过程中使用Iterator.remove(),可以避免,在遍历过程中由于集合结构的变化(如直接调用remove()方法)而引发的ConcurrentModificationException。
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public static void main(String[] args) {coll = new ArrayList();coll.add(123);coll.add(456);coll.add(789);coll.add(new String("Tom"));Iterator iterator = coll.iterator();// hasNext():判断是否还有下一个元素while (iterator.hasNext()) {// next():1、指针下移,2、将下移以后集合位置上的元素返回System.out.println(iterator.next());}// 错误方式一:Iterator iterator = coll.iterator();while((iterator.next()) != null){System.out.println(iterator.next());}// 错误方式二:/*每次调用coll.iterator().hasNext() 和 coll.iterator().next()都会创建一个新的迭代器,而不是使用已经存在的iterator变量,因为,每次调用coll.iterator()都会返回一个新的迭代器,并且迭代器是独立的,它们不会互相影响,因此循环永远不会结束。*/// 这个 while 会死循环while (coll.iterator().hasNext()){System.out.println(coll.iterator().next());}
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public static void main(String[] args) {Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add("Tom");coll.add(789);Iterator iterator = coll.iterator();// hasNext():判断是否还有下一个元素while (iterator.hasNext()) {Object obj = iterator.next();if ("Tom".equals(obj)) {// 使用迭代器的remove()方法,删除当前元素iterator.remove();System.out.println("Removed: " + obj);} else {System.out.println("Kept: " + obj);}}
}
/*
打印的是,Kept: 123Kept: 456Removed: TomKept: 789
*/
Collection - List
List接口的实现类有:ArrayList LinkedList Vector
1、List 接口的常用方法:void add(int index, Object ele):在index位置插入ele元素boolean addAll(int index, Collection eles):从index位置开始,将eles中的所有元素添加进来Object get(int index):获取指定index位置的元素int indexOf(Object obj):返回obj在集合中首次出现的位置,如果不存在 返回-1int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置Object remove(int index):移除指定index位置的元素,并返回此元素Object set(int index, Object ele):设置指定index位置的元素为eleList subList(int fromIndex, int toIndex):返回,从fromIndex到toIndex位置的子集合2、总结:常用方法增:add(Object obj)删:remove(int index) / remove(Object obj)改:set(int index, Object ele)查:get(int index)插:add(int index, Object ele)长度:size()遍历:Iterator迭代器方式增强for循环普通的循环
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public static void main(String[] args) {ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");list.add(456);System.out.println("list=" + list); // list=[123, 456, AA, 456]// void add(int index, Object ele):在index位置插入ele元素 -----------------------------------list.add(1, "BB");System.out.println(list); // [123, BB, 456, AA, 456]// boolean addAll(int index, Collection eles):从index位置开始,将eles中的所有元素添加进来 -----------------------------------List<Integer> list1 = Arrays.asList(1, 2, 3);list.addAll(list1);System.out.println(list); // [123, BB, 456, AA, 456, 1, 2, 3]// Object get(int index):获取指定index位置的元素 -----------------------------------System.out.println(list.get(1)); // BB// int indexOf(Object obj):返回obj在集合中首次出现的位置 -----------------------------------System.out.println(list.indexOf(456)); // 2System.out.println(list.indexOf(456789)); // -1// int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 -----------------------------------System.out.println(list.lastIndexOf(456)); // 4// Object remove(int index):移除指定index位置的元素,并返回此元素 -----------------------------------Object o = list.remove(0);System.out.println(o); // 123System.out.println(list); // [BB, 456, AA, 456, 1, 2, 3]// Object set(int index, Object ele):设置指定index位置的元素为ele -----------------------------------list.set(1, "CC");System.out.println(list); // [BB, CC, AA, 456, 1, 2, 3]// List subList(int fromIndex, int toIndex):返回,从[fromIndex, toIndex)位置的子集合 -----------------------------------List list2 = list.subList(0, 3);System.out.println(list2); // [BB, CC, AA]// 遍历List -----------------------------------// 遍历方式 - 1、迭代器Iterator iterator = list.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}// 遍历方式 - 2、增强forfor (Object obj: list){System.out.println(obj);}// 遍历方式 - 2、普通forfor (int i = 0;i < list.size();i++){System.out.println(list.get(i));}
}
ArrayList
1、内部存储用的数据结构,是用**数组(动态调整大小)**实现,默认初始容量为10。每次扩容大小是增加50%(在java8版本以及之后的版本,java6使用的是1.5倍)。2、优点:使用数组实现,因此,内部元素可以通过索引实现快速随机访问。缺点:a. 从ArrayList中间位置插入和删除元素,都需要循环移动其他元素元素的位置。b. 数组空间不够需要扩容时,会开辟一个新的数组,把旧的数组元素拷贝过去,比较耗性能。c. 线程不安全。3、扩容java8及之后,扩容计算方法:int newCapacity = oldCapacity + (oldCapacity >> 1);这意味着,在原来数组大小的基础上,扩大50%作为新数组容量的大小。java6的计算方法:int newCapacity = (oldCapacity * 3)/2 + 1;这意味着,在原来数组大小的基础上,扩大1.5倍作为新数组容量的大小。4、"总之,ArrayList基于数组实现 查改快,增删慢,线程不安全""在需要做一次性插入 和 多次查询业务时,可以使用此集合,但是,ArrayList不保证线程安全,只能在单线程时候做使用"
源码解析
"源码":class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
"AbstractList<E>":是List接口第一抽象类"RandomAccess":RandomAccess接口是一个标志接口(Marker)它支持快速随机访问"Cloneable":支持克隆"java.io.Serializable":RandomAccess接口也是是一个标志接口(Marker) 它支持序列化和反序列化
"属性":private static final long serialVersionUID = 8683452581122892189L; // 序列化编号private static final int DEFAULT_CAPACITY = 10; // 使用无参构造器时,第一次扩容的数组默认大小10private static final Object[] EMPTY_ELEMENTDATA = {}; // 用于空实例的共享空数组实例// 用于,默认大小的空实例的共享空数组实例。// 我们将其与 EMPTY_ELEMENTDATA 区分开来,以了解添加第一个元素时扩容多少。// MARK:无参构造函数,使用该数组初始化,与 EMPTY_ELEMENTDATA 的区别主要是区分作用,用来减少空数组的存在,优化内存使用 1.8后的优化private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};transient Object[] elementData; // 底层的数据结构Object类型的数组private int size; // 记录数组中元素的个数"无参构造器 - 构造一个初始容量为10的一个数组":public ArrayList() {// private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*这里其实是赋值了一个共享的空数组,数组在第一次添加元素时,会判断 elementData 是否等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,假如等于,则会初始化容量为 DEFAULT_CAPACITY 也就是10*/this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}"带参构造器 - 1":
int initialCapacity为ArrayList 底层数组初始的长度,构造一个指定长度的数组
public ArrayList(int initialCapacity) {// 参数合法性检验if (initialCapacity > 0) {// 创建一个长度为 initialCapacity 的数this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {// 将原有的空数组EMPTY_ELEMENTDATA赋给底层数组elementDatathis.elementData = EMPTY_ELEMENTDATA;} else {// 参数不合法抛出IllegalArgumentException异常throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}
}"带参构造器 - 2"
"Collection<? extends E> c":c是泛型E的子类,构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray(); // 将c集合中的数据拷贝到a数组中if ((size = a.length) != 0) { // 判空并给size赋值if (c.getClass() == ArrayList.class) { // 如果c是ArrayList类的对象之间将a数组地址赋值给elementData数组elementData = a; } else {// 进行拷贝elementData = Arrays.copyOf(a, size, Object[].class);}} else {// 如果为c集合为空,则将原有的空数组EMPTY_ELEMENTDATA赋给底层数组elementDataelementData = EMPTY_ELEMENTDATA;}
}"扩容机制"
private Object[] grow() { // 数组容量不足时,直接调用的扩容方法,返回一个Object数组return grow(size + 1);
}private Object[] grow(int minCapacity) { // 数组拷贝的实现,newCapacity(minCapacity) 为实际的扩容大小return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
}private int newCapacity(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;//原来数组的长度int newCapacity = oldCapacity + (oldCapacity >> 1); //新数组的长度,在原来数组的长度上加原来数组的二分之一if (newCapacity - minCapacity <= 0) { //如果新数组的长度小于等于size+1 比如原来数组长度为0或者1,那么新数组长度也为0或者1无法体现扩容,则需要重新处理:处理如下if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)// 判断,现在的数组,是否为无参构造器创建的数组,如果是,就返回DEFAULT_CAPACITY,即无参构造器第一次扩容为10return Math.max(DEFAULT_CAPACITY, minCapacity);if (minCapacity < 0) // 参数无效抛出异常throw new OutOfMemoryError();return minCapacity; //扩容+1;}// MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8return (newCapacity - MAX_ARRAY_SIZE <= 0) // 如果,新数组长度,大于最大扩容边界需要做特殊处理? newCapacity: hugeCapacity(minCapacity); // 特殊处理
}private static int hugeCapacity(int minCapacity) {// 参数合法性检验if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) // 如果,size+1大于最大扩容边界,则扩容到 Integer.MAX_VALUE(2 的 31 次方 - 1),否则扩容到最大扩容边界? Integer.MAX_VALUE: MAX_ARRAY_SIZE;
}
Vector
1、基于 数组(动态调整大小) 数据结构实现,初始容量是10。2、优点:线程安全。缺点:效率低,增加元素、删除元素、查找元素都很慢。
LinkList
1、内部存储用的数据结构,是用双向链表实现。2、优点:使用链表实现,适合动态的插入和删除。缺点:a. 随机访问元素的速度相对较慢。b. 基于链表数据结构的实现,占用的内存空间比较大(除了保存数据本身,还要保存指针信息)。"总之",LinkedList,底层通过双向链表的形式实现,增删快,遍历和查询慢,线程不安全。LinkedList,底层使用双向链表的形式存储数据,不用向ArrayList存在地址浪费,并且在增删时效率高,我们可以在需要经常增删时使用此集合来提高我们的效率。
"源码":public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable与 ArrayList 不同的是,LinkedList 继承的是 AbstractSequentialList,但,AbstractSequentialList 也是继承自 AbstractList,其他和 ArrayList 相同
"属性"transient int size = 0; // 记录数据多少transient Node<E> first; // 双向链表的头结点transient Node<E> last; // 双向链表的尾结点"构造方法"
public LinkedList() {} // LinkedList的构造方法,是一个空方法,此时指针变量first和last的初始值都为null。public LinkedList(Collection<? extends E> c) { // 拷贝的构造器this();addAll(c); // 将所有c中的数据拷贝过来
}"链表节点静态类,储存的数据的实体Node"
private static class Node<E> {E item; // 需要储存的数据Node<E> next; // 后继,连接下一个数据,如果它是最后一个,则为nullNode<E> prev; // 前驱,连接上一个数据,如果它是第一个,则为nullNode(Node<E> prev, E element, Node<E> next) { // Node的构造器this.item = element;this.next = next;this.prev = prev;}// 明显看出,这是一个双向链表节点,item是用来存放节点值,next是尾指针指向下一个节点,prev是头指针指向前一个节点。
}
这篇关于集合框架 Collection - List(Arrays.asList)- 迭代器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!