首页 > 编程 > Java > 正文

Java集合Collection

2019-11-06 06:07:45
字体:
来源:转载
供稿:网友

java集合Collection


1. 集合的特点

集合是存储一组对象的容器,长度可变。集合类存放的都是对象的引用,而非对象本身。任意类型的数据都可以存到集合,存进去后的元素类型默认是Object。集合类型主要有3种:set(集)、list(列表)和map(映射)。其中Set代表无序、不可重复的集合;List代表有序、重复的集合;而Map则代表具有映射关系的集合。

2. 集合框架图

这里写图片描述

Collection单列集合

(接口)List: 实现类 ArrayList LinkedList Vector (接口)Set: 实现类 HashSet TreeSet LinkedHashSet

Map双列集合

(接口)map: 实现类 HashMap Hashtable TreeMap PRoperties

ArrayList、Vector、HashMap、HashSet的默认初始容量、加载因子、扩容增量? http://www.cnblogs.com/xiezie/p/5511840.html

3. Collection接口

特点 Collection用于表示一组单值对象的集合,这些对象也称为元素。Collection接口定义了一系列抽象方法,规范了对单值类型的集合的操作标准。Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。常用方法 获取存储的元素总数:size(*)添加元素:add、addAll(*)迭代所有元素:iterator(*)移除元素:remove、removeAll清空集合:clear是否是空集合:isEmpty是否包含某个元素:contains、containsAll取交集:retainAll(Collection)转换成传统的数组类型:toArray

Collections

java.util.Collections是集合类的一个工具类/帮助类,此类不能实例化,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。常用方法 sort 排序max/min 求最值fill 填充reverse 反转

代码

Integer[] arr = new Integer[] { 2, 1, 3 }; List<Integer> list1 = Arrays.asList(arr);List<Integer> list2 = new ArrayList<>(list1);list2.add(4);System.out.println(list2);//[2, 1, 3, 4]Collections.reverse(list2);System.out.println(list2);//[4, 3, 1, 2]System.out.println(Collections.max(list2));//4System.out.println(Collections.min(list2));//1Collections.sort(list2);System.out.println(list2);//[1, 2, 3, 4]Collections.fill(list2, 2);System.out.println(list2);//[2, 2, 2, 2]

4. List接口

元素特点 有序(存入和取出的顺序一致);可重复;集合中的每个元素都有其对应的顺序索引。JDK API中List接口的实现类常用的有:ArrayListLinkedListVector。常用方法 List 除了从Collection集合中继承的方法外,添加了一些根据索引来操作集合元素的方法。新增的方法: 删除:remove(int index)修改:set(int index,Object obj) 获取:get(int index)插入:add(int index,Object obj) addAll(int index, Collection c) 查找某个对象的索引(从前往后):indexOf(Object o) 查找某个对象的索引(从后往前): lastIndexOf(Object obj)subList(int fromIndex, int toIndex):返回列表中指定的 fromIndex(包括)和 toIndex(不包括)之间的部分视图。ListIterator listIterator():返回列表迭代器对象ListIterator listIterator(int index):返回从指定位置开始的列表迭代器对象ListIterator接口独有的方法:(可以反向遍历) add(E e) 将指定的元素插入列表(可选操作)。boolean hasprevious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。 int nextIndex() 返回对 next 的后续调用所返回元素的索引。E previous() 返回列表中的前一个元素。int previousIndex() 返回对 previous 的后续调用所返回元素的索引。void remove() 从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。 void set(E e)用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。

ArrayList实现类

ArrayList 是 List 接口的典型实现类,本质上,ArrayList是对象引用的一个变长数组。List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 。默认初始容量为10。当集合容量不够时,默认是增加原来集合元素个数的一半特点: 底层是数组结构;适合搜索,不适合增删改(空间是连续的); 版本较新,线程不安全,不同步,效率比较高。

构造方法摘要 :

ArrayList() 构造一个初始容量为 10 的空列表。 ArrayList(Collection<? extends E> c) 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表

和数组的转换

调用Arrays的asList(Abject o)方法

代码

Integer[] arr = new Integer[] { 1, 2, 3 };List<Integer> list1 = Arrays.asList(arr);// list1.add("c");//java.lang.UnsupportedOperationExceptionList<Integer> list2 = new ArrayList<>(list1);list2.add(4);//可以使用

java.lang.UnsupportedOperationException是不支持功能异常,常常出现在使用Arrays.asList()后调用add,remove这些方法时。 这是由于:    Arrays.asList() 返回java.util.ArraysArrayList,而不是ArrayList。ArraysArrayList和ArrayList都是继承AbstractList,remove,add等方法在AbstractList中是默认throw UnsupportedOperationException而且不作任何操作。ArrayList override这些方法来对list进行操作,但是Arrays$ArrayList没有override remove(int),add(int)等,所以throw UnsupportedOperationException。  解决方法是转换为ArrayList!

LinkedList

对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高。特点: 底层采用的是链表结构适合做增删改,不适合搜索(空间是不连续)

特有的方法

将元素插入列表开头:addFirst(E e)将元素插入列表结尾:addLast(E e)返回此列表的第一个元素:getFirst() 返回此列表的最后一个元素:getLast() 移除并返回此列表第一个元素: removeFirst()移除并返回此列表的最后一个元素: removeLast()//等等特殊方法

LinkedList内部有个内部类Node,这样

private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; }}LinkedList:双向链表除了保存数据,还定义了两个变量:prev变量记录前一个元素的位置next变量记录后一个元素的位置删除元素时,只需改变前后两个元素的prev和next值。

Vector

古老的实现类、线程安全的,但效率要低于ArrayList。特点: 版本较老,线程安全的,同步的,效率比较低底层采用的是数组结构

比较

ArrayList和Vector 的对比 特点 底层:数组结构 ArrayList 线程不同步,效率高,不安全(单线程访问时) Vector 线程同步,效率低,安全(多线程访问时)ArrayList和LinkedList的对比
底层结构 常用方法 特点
ArrayList 数组 List接口中的方法 搜索速度比较快,而增删改较慢(空间是连续的)
LinkedList 链表 List接口中的方法和特有方法 增删改速度比较快,而搜索比较慢(空间是不连续的)

5. Set接口

元素特点 **无序的;**Set集合说无序,这个无序是说在内存中保存没有顺序,其中的TreeSet等表现出来的有序,也只是在遍历时显示的有顺序。元素不能重复;不支持索引; Set集合 一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素,对 e1 和 e2,并且最多包含一个 null 元素。Set接口是Collection的子接口,set接口没有提供额外的方法。Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,最终只能添加一个。Set 判断两个对象是否相同不是使用 == 运算符, 而是Hash系列的根据Set equals 和hashcode方法,有序系列的根据compareTo或compare方法。Set接口的实现类: 1)HashSet:按照哈希值来存取集合中的对象2)TreeSet:有序的对象集3)LinkedHashSet:按照哈希算法来存取集合中的对象,遍历输出时保持元素的添加顺序

HashSet

HashSet是Set接口的典型实现,大多数情况使用Set集合时都使用这个实现类。HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。当向HashSet集合中添加元素时,HashSet会调用该对象的HashCode()方法来得到这个对象的hashCode值,然后根据hashCode值决定该对象在HashSet 中的存储位置。 2)特点: 底层采用哈希表结构,是无序的;HashSet**线程不安全;**集合元素可以为null。

3)为什么用哈希算法来存储集合中的元素?

因为Set集合想要保证不重复性,因此每一个对象放入到集合中,就意味着要和集合中的每一个元素都比较一次,那么这样的效率极低,所以用哈希算法来存储,因为hashCode不相等的两个对象肯定是两个不相同的对象(散列函数的结论),如果HashCode相同,那就再判断equals方法,这样就大大减少了工作量,提高了效率。

4)对于存放在Set容器中的对象,对应的类一定要写equals()和hashCode(Object obj)方法,以实现对象相等规则。

5)重写hashCode方法的基本原则: 在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值;当两个对象的equals方法比较返回true时,这两个对象的hashCode()方法返回值也应该相同。对象中用作equals方法比较的属性,都应该用来计算hashCode值。6) 不同对象的哈希值有可能一样如果两个对象的equals 比较结果为true,则哈希值肯定一样两个对象的哈希值一样,但equals结果不一定为true

LinkedHashSet

1)LinkedHashSet是HaseSet的子类。是根据元素的hashCode值来决定元素的存储位置,但同时使用链表维护元素的次序,使得元素看起来像是插入顺序保证的。2)特点 底层是链表和哈希表的双实现;存入和取出的顺序一致;不允许元素重复。

TreeSet

1)TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。2)特点: 底层采用二叉树结构,实现对元素的排序功能元素不能重复

3)TreeSet有两种排序方法:自然排序和定制排序

要添加的元素类型自己实现Comparable,重写compareTo方法在创建TreeSet对象时,指定Comparator接口对象,重写compare方法

4)特殊方法:

first(): 返回此 set 中当前第一个(最低)元素。 floor(E e) : 返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null。last(): 返回此 set 中当前最后一个(最高)元素。 lower(E e) : 返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。 等等

6. Map接口

特点

Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value ;Map中的key和value都可以是任何引用类型的数据,value可以重复; Map中的key用Set来存放,不允许重复,即作为map的key类型,需重写hashCode()和equals()方法;常用String类作为Map的键,key和value之间存在一对一的关系,即通过指定的key能找到唯一、确定的value值。常用方法: clear():从此映射中移除所有映射关系(可选操作)boolean containsKey(Object key): 如果此映射包含指定键的映射关系,则返回 true。boolean containsValue(Object value): 如果此映射将一个或多个键映射到指定值,则返回 true。 entrySet(): 返回此映射中包含的映射关系的 Set 视图。boolean equals(Object o): 比较指定的对象与此映射是否相等。V get(Object key) : 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 int hashCode(): 返回此映射的哈希码值。boolean isEmpty() : 如果此映射未包含键-值映射关系,则返回 true。Set keySet() : 返回此映射中包含的键的 Set 视图。V put(K key, V value) : 将指定的值与此映射中的指定键关联(可选操作)。void putAll( m) : 从指定映射中将所有映射关系复制到此映射中(可选操作)。 V remove(Object key): 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。int size(): 返回此映射中的键-值映射关系数。Collection values() : 返回此映射中包含的值的 Collection 视图。

Map继承树

这里写图片描述Map常用的实现类:HashMapTreeMapProperties。

HashMap

1)HashMap是Map接口使用频率最高的类,允许null值和null键,与HashSet一样,不保证映射顺序。2)HashMap**判断两个key相等的标准是**:两个key通过equals()方法返回true,并且hashCode值也相同。3)HashMap**判断两个value相等的标准是**:两个value通过equals()方法返回true。

4)特点:

底层是哈希表结构键是无序的;一般要重写 hashcode和equals方法;版本比较新,线程不安全、不同步的、效率高,允许null键null值。

5)LinkedHashMap是HashMap的子类,与LinkedHashSet类似,LinkedHashMap可以维护Map的迭代顺序:迭代顺序与key-value对的插入顺序一致,

TreeMap

1)TreeMap存储key-value对时,需要根据key-value对进行排序。TreeMap可以保证所有的key-value对处于有序状态。2)TreeMap的key的排序: 自然排序:TreeMap的key必须实现Comparable接口,而且所有的key应该是同一个类的对象,否则将会抛出ClassCastException;定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对key进行排序,此时不需要Map的key实现Comparable接口。3)TreeMap判断两个key相等的标准:两个ket通过compareTo()方法或Compare()方法返回0;4)若使用自定义类作为TreeMap的key,属性类需要重写equals()和hashCode()方法,且equals()方法返回true时,compareTo()返回0。5)特点: 底层是二叉树,可以实现对键排序

HashTable

1)HashTable是个古老的Map实现类,线程安全。2)与HashMap不同,HashTable不允许出现null作为key和value。3)与HashMap一样,HashTable也不能保证key-value对的顺序。4)HashTable判断两个key相等、两个value相等的标准与HashMap相同。

Properties

1)Properties是HashTable的子类,该类用于处理属性文件。2)特点: 用于读取和写入属性文件(Xxx.properties)3)属性文件格式要求 键值对;键和值都是String类型。4)常用方法 getProperty(String key): 获取属性 setProperty(String key,String value):设置属性load(InputStream inStream) :加载属性文件的数据到Properties集合中list(PrintStream out) :打印Properties集合中的元素到指定设备上store(OutputStream out, String comments) :将集合中的内容存储到文件中

7. Iterator和Iterable

Iterable

Iterator是迭代器类,而Iterable是为了只要实现该接口就可以使用foreach,进行迭代.Iterable中封装了Iterator接口,只要实现了Iterable接口的类,就可以使用Iterator迭代器了。这个迭代器是用接口定义的 iterator方法提供的。也就是iterator方法需要返回一个Iterator对象。

集合Collection、List、Set都是Iterable的实现类,所以他们及其他们的子类都可以使用foreach进行迭代。

//Iterable JDK源码//可以通过成员内部类,方法内部类,甚至匿名内部类去实现Iteratorpublic interface Iterable<T>{ Iterator<T> iterator();}

Iterator

包含3个方法: hasNext(), next() , remove()。一开始迭代器在所有元素的左边,调用next()之后,迭代器移到第一个和第二个元素之间,next()方法返回迭代器刚刚经过的元素。hasNext()若返回True,则表明接下来还有元素,迭代器不在尾部。remove()方法必须和next方法一起使用,功能是去除刚刚next方法返回的元素。

为什么一定要去实现Iterable这个接口呢? 为什么不直接实现Iterator接口呢?

Collection接口实现了Iterable接口,但并不直接实现Iterator接口。因为Iterator接口的核心方法next()或者hasNext(),是依赖于迭代器的当前迭代位置的。如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。多个迭代器是互不干扰的。

8. 遍历集合的几种方式

使用迭代器Iterator的方式。

语法

Iterator iter = coll.iterator();while(iter.hasNext()){ Object obj = iterm.next();} 遍历过程中,不允许做集合元素的增删改的,只能使用Iterator本身的remove方法做删除。

使用增强for循环的方式。

语法

for(元素类型 元素名:集合或数组名){ 访问 元素名 syso(obj);}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表