Java 集合总结

先送上集合整体结构图一张
这里写图片描述
补充一点关于 Map 的实现类还有一个 HashTable,声明如下:

public class Hashtable<K,V>extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {

虽然这个类我们不常用,但是经常使用它的子类 Properties

public class Properties extends Hashtable<Object,Object> {

下面就来详细分析一下各个类的特征以及使用 。

java 集合可以分为 Collection 和 Map 两种体系
Collection 接口:
    Set : 元素无序,不可重复的集合 相当于高中的集合
    List : 元素有序,可重复的集合 相当于动态数组

Map 接口: 具有映射关系的键值对

Collection 接口是List Set Queue 接口的父接口,该接口里定义的方法既可以用于操作 Set 集合,也可以操作 List 和 Queue 集合 。
JDK 没有提供 Collection 的直接实现,而是提供更具体的子类接口的实现 。

Collection 的接口方法, 集合与数组转换操作:toArray()

使用 Lterator 接口遍历集合元素
Lterator 对象称为迭代器,主要用于遍历 Collection 集合中的元素 。

所有实现了 Collection 接口的集合类都有一个 iterator()方法 。用于返回一个实现了 Lterator 接口的对象 。

Lterator 仅用于遍历集合 。本身没有封装对象的能力,需要给一个要遍历的数组 。

List 集合中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引 。
List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素 。

List 接口的实现类常用的有:ArrayList、LinkedList 和 Vector 。

ArrayList 是 List 接口的典型实现类 。
本质上,ArrayList是对象引用的一个变长数组 。
ArrayList 是线程不安全的,而 Vector 是线程安全的,即使为保证 List 集合线程安全,也不推荐使用 Vector 。

Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合 。

对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高 。

Set 接口是 Collection 的子接口,Set 接口没有提供额外的方法 。Set 集合不允许包含相同的元素,如果把两个相同的元素加入同一个 Set 集合中,则添加操作失败 。Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals( ) 方法 。

HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能 。不能保证元素的排列顺序 。HashSet 不是线程安全的 。集合元素可以是 null 。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置 。

HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等 。

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功 。
对于存放在 Set 容器中的对象,对应的类一定要重写 equals() 和 hashCode(Object obj) 方法,以实现对象相等规则 。

重写 hashCode() 方法的基本原则
在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值 。当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等 。对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值

LinkedHashSet 是 HashSet 的子类
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的 。
LinkedHashSet 插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能 。
LinkedHashSet 不允许集合元素重复。

TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态 。TreeSet 有两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序 。

自然排序:实现 Comparable 接口的 comparaTo() 方法
定制排序:实现 Comparator 接口的 compara() 方法

自然排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列 。如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口 。实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小 。

有些类已经实现了 Comparable 接口,比方说包装类 String、Date 类 。

向 TreeSet 中添加元素时,只有第一个元素无须比较 compareTo() 方法,后面添加的所有元素都会调用 compareTo() 方法进行比较 。因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象 。

对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值 。当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0 。

Map 中的 key 用 Set 来存放,不允许重复,即同一个 Map 对象所对应的类,须重写 hashCode() 和 equals()方法 。常用 String 类作为 Map 的“键”。
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value 。

HashMap 是 Map 接口使用频率最高的实现类 。允许使用 null 键和 null 值,与 HashSet 一样,不保证映射的顺序 。

HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等 。
HashMap 判断两个 value 相等的标准是:两个 value 通过 equals() 方法返回 true 。

LinkedHashMap 是 HashMap 的子类
与 LinkedHashSet 类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致 。

TreeMap 存储 Key-Value 对时,需要根据 key-value 对进行排序 TreeMap 可以保证所有的 Key-Value 对处于有序状态 。

TreeMap 的 Key 的排序:
    自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException 。
    定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口 。

TreeMap 判断两个 key 相等的标准:两个 key 通过 compareTo() 方法或者 compare() 方法返回 0 。若使用自定义类作为 TreeMap 的 key,所属类需要重写 equals() 和 hashCode() 方法,且 equals() 方法返回 true 时,compareTo() 方法应返回 0 。

Hashtable 是个古老的 Map 实现类,线程安全 。与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value 。

Properties 类是 Hashtable 的子类,该对象用于处理属性文件 。由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型 。存取数据时,建议使用 setProperty(String key,String value) 方法和 getProperty(String key) 方法 。

Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);

操作数组的工具类:Arrays
操作集合的工具类:Collections

reverse(List):反转 List 中元素的顺序 。
shuffle(List):对 List 集合元素进行随机排序 。
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序 。
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序 。
swap(List,int, int):将指定 List 集合中的 i 处元素和 j 处元素进行交换 。
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素 。
Object min(Collection) 与 max 类似 。
Object min(Collection,Comparator) 与 max 类似 。
int frequency(Collection,Object):返回指定集合中指定元素的出现次数 。
void copy(List dest,List src):将 src 中的内容复制到 dest 中 。
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值 。

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题 。


Collection 和 Collections的区别
答:Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List 。
Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作 。


说出 ArrayList,Vector, LinkedList 的存储性能和特性
答:ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector 由于使用了 synchronized 方法(线程安全),通常性能上较 ArrayList 差,而 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快 。


HashMap 和 Hashtable 的区别
答:HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都实现了 Map 接口,主要区别在于 HashMap 允许空(null)键值(key), 由于非线程安全,效率上可能高于 Hashtable 。
HashMap 允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许 。
HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsValue 和 containsKey 。
最大的不同是,Hashtable 的方法是 Synchronize 的,而 HashMap 不是 。


ArrayList 和 Vector 的区别 , HashMap 和 Hashtable 的区别
答:就 ArrayList 与 Vector 主要从二方面来说
一. 同步性 : Vector 是线程安全的,也就是说是同步的,而 ArrayList 是线程序不安全的,不是同步的 。
二. 数据增长 : 当需要增长时 , Vector 默认增长为原来一培,而 ArrayList 却是原来的一半 。
就 HashMap 与 Hashtable 主要从三方面来说 。
一. 历史原因 : Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是Java 1.2 引进的 Map 接口的一个实现 。
二. 同步性 : Hashtable 是线程安全的,也就是说是同步的,而 HashMap 是线程序不安全的,不是同步的 。
三. 值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或value ,而 Hashtable 不允许为空,key 和 value 都不能为空 。


如何高效地判断数组中是否包含某特定值?

检查数组中是否包含特定值的四种不同方法:

    1 使用 List

Arrays.asList(arr).contains(targetValue);

    2 使用 Set

Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);

    3 使用一个简单循环

for(String s: arr){
        if(s.equals(targetValue))
            return true;
    }
    return false;

    4 使用 Arrays.binarySearch( ) :二分法查找,需要是有序数组 。

int a =  Arrays.binarySearch(arr, targetValue);
    if(a >= 0)
        return true;
    else
        return false;

通过测试,记录代码执行的时间,可以得出结论:
使用简单循环的方法比使用其他任何集合效率更高 。许多开发者会使用第一种方法,但是它并不是高效的 。
将数组压入Collection 类型中,需要首先将数组元素遍历一遍,然后再使用集合类做其他操作 。
如果使用 Arrays.binarySearch() 方法,数组必须是已排序的 。
实际上,如果你需要借助数组或者集合类高效地检查数组中是否包含特定值,一个已排序的列表或树可以做到时间复杂度为 O(log(n)),Hashset可以达到 O(1) 。

发布了49 篇原创文章 · 获赞 44 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览