集合(上)
Collection和Map两种集合体系
-
Collection接口:单列数据,定义了存取一组对象的方法的集合
- List:元素有序、可重复的集合
- Vector
- ArrayList
- LinkedList
- Set:元素无序、不可重复的集合
- HashSet
- LinkedHashSet
- TreeSet
- HashSet
- List:元素有序、可重复的集合
-
Map接口:双列数据,保存具有映射关系“key-value对”的集合
- HsahTable
- Properties
- HashMap
- LinkedHashMap
- TreeMap
- HsahTable
Collection接口的方法
-
添加:add(Object obj)、addAll(Collection coll)
-
获取有效元素的个数:int size()
-
清空集合:void clear()
-
是否是空集合:boolean isEmpty()
-
contains(Object obj):判断当前集合中是否包含obj,在判断时会调用obj对象所在类的equals()方法
-
containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中(全包含)
-
remove(Object obj):从当前集合中移除obj元素。
-
removeAll(Collection coll1):即去差集、从当前集合中移除coll1中所有的元素
Collection coll = new ArrayList(); coll.add(123); coll.add(456); Collection coll1 = Arrays.asList(123,4567); coll.removeAll(coll1); System.out.println(coll);//[456]
-
retainAll(Collection coll1)即求交集:获取当前集合和coll1集合的交集,并返回给当前集合
Collection coll = new ArrayList(); coll.add(123); coll.add(456); Collection coll1 = Arrays.asList(123,4567); coll.retainAll(coll1); System.out.println(coll);//[123]
-
equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同,若为新的类则该类需要重写equals()方法,否则调用的是Object类的方法无法达到比较目的(若为基本数据类型,则add()方法已自动装箱为包装类,包装类已重写了equals()方法)
-
hashCode():返回当前对象的哈希值
-
toArray():集合 --> 数组:
Object[] arr = coll.toArray();
Arrays.asList():数组 --> 集合:
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
-
iterator():返回Iterator接口的实例,用于遍历集合元素
Iterator迭代器接口的方法
【说明】提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。Collection接口继承了java.lang.Iterable接口,该接口有一个**iterator()**方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
-
hasNext() 和next():若下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常
//hasNext():判断是否还有下一个元素 while(iterator.hasNext()){ //next():①指针下移 ②将下移以后集合位置上的元素返回 System.out.println(iterator.next()); }
-
迭代器的执行原理
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
-
default void remove():通过迭代器对象的remove方法删除元素,而不是集合对象的remove方法
-
使用增强for循环foreach循环遍历集合元素的底层用的就是Iterator迭代器!
-
增强for循环foreach的面试题:
String[] arr = new String[]{"MM","MM","MM"}; //方式一:普通for赋值 for(int i = 0;i < arr.length;i++){ arr[i] = "GG"; }//{"GG","GG","GG"} //方式二:增强for循环 for(String s : arr){ s = "GG";//对新的变量赋值不改变原数组的数据 }//{"MM","MM","MM"}
-
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在集合中首次出现的位置
- int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index, Object ele):设置指定index位置的元素为ele
- List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
操作 | 方法 |
---|---|
增 | 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循环 ③ 普通循环
ArrayList()源码分析
-
jdk 7情况下:(对象的创建类似於单例的饿汉式)
ArrayList list = new ArrayList();底层创建了长度是10的Object[]数组
list.add(123);//elementData[0] = new Integer(123);//自动装箱用包装类添加数据
…
list.add(11);//如果此次的添加导致底层Object[]数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。(Arrays.copyOf())
结论:建议开发中使用带参的构造器避免多次扩容:ArrayList list = new ArrayList(int capacity)
-
jdk 8中ArrayList的变化:(类似於单例的懒汉式,延迟了数组的创建,节省内存)
ArrayList list = new ArrayList();底层Object[]数组,初始化为{}.并没创建长度为10的数组
list.add(123);第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]
…
后续的添加和扩容操作与jdk 7无异。
Vector的源码分析
-
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的Object[ ]数组。
-
在扩容方面,默认扩容为原来的数组长度的2倍。
面试题:ArrayList、LinkedList、Vector三者的异同?
-
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
-
不同:
List实现类 底层结构 同步 特点 Vector 可变数组Object[ ] 单线程(同步低效) 老 ArrayList 可变数组Object[ ] 多线程(异步高效) 查询快 LinkedList 双向链表 多线程(异步高效) 增删操作快