Java集合 Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

每博一文案

别把人生,输给心情
师父说:心情不是人生的全部,却能左右人生的全部。
你有没有体会到,当你心情好的时候,生活仿佛阳光灿烂,顺风顺水,
当你心情不好的时候,似乎周围的一切都糟糕透了。
有时候,我们不是输给了别人,而是败给了坏心情的自己。
人活着就像一个陀螺,为了生活不停的转动,永远都有忙不完的事。
有时候又像沙漠中的骆驼,背负着重担努力地前行,却不知道哪里才是终点。
先现在情绪低落,只是因为陷进了自我纠缠的陷阱,等到熬过了这段苦难,
你会发现你所纠结的东西,真的只是无关痛痒的小事。
生活就像天气,不会总是晴天,也不会一直阴雨,喜欢和讨厌是次要的,关键是你要学会调整自己。
心静了,才能听见自己的心声,心清了,才能照见万物的本性。
假如任由坏情绪累积和蔓延,很多事只会变得越来越糟糕,
既然做不到让所有人都满意,为何不努力让自己开心?
生活是你自己的,喜怒悲欢都由你自己决定,记得别被坏情绪束缚住,
不要让你的人生,输给了心情。
                                      ——————   一禅心灵庙语
目录
  • Java集合 Map 集合 与 操作集合的工具类: Collections 的详细说明

    • 每博一文案
    • 1. Map接口概述
    • 2. Map接口:常用方法
    • 3. Map实现类之一:HashMap

      • 3.1 HashMap的存储结构
      • 3.2 HashMap源码中的重要常量
      • 3.3 HashMap的存储结构:JDK 1.8之前 / JDK 1.8之后

        • 3.3.1 JDk 1.8 之前
        • 3.3.2 JDk 1.8 及之后
        • 3.3.3 JDK8 HashMap 集合添加元素的过程
        • 3.3.4 JDK8 HashMap 进行 "扩容"和 "树形化"
        • 3.3.5 总结:JDK1.8 相较于之前的变化:
    • 4. Map实现类之二:LinkedHashMap
    • 5. Map实现类之三:TreeMap
    • 6. Map实现类之四:Hashtable
    • 7. Map实现类之五:Properties
    • 8. Map 接口下的集合遍历方式
    • 9. Collections工具类

      • 9.1 Collections常用方法
    • 10. 总结:
    • 11. 最后:

1. Map接口概述

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

2. Map接口:常用方法

添加、删除、修改操作:

V put(K key,V value);  // 将指定的 key 和 value 值添加/修改到该集合当中。
void putAll(Map<? extends K,? extends V> m);  // 将m中的所有key-value对存放到当前map集合当中
V remove(Object key);  // 移除指定key的key-value对,并返回value
void clear();  // 清空当前map中的所有数据
int size();  // 返回此集合中存储的元素数据(键值对)的数量。

举例:

import java.util.HashMap;
import java.util.Map;
public class MapTest {
    public static void main(String[] args) {
        // Map 接口 , HashMap实现类,多态,<String,Integer> 泛型
        Map<String,Integer> map = new HashMap<String,Integer>();
        // 添加元素数据:
        map.put("zhangsan",66);
        map.put("lisi",89);
        map.put("wangwu",97);
        map.put("lihua",99);
        System.out.println(map);
        int size = map.size();  // 返回该集合中存储的键值对的数量。
        System.out.println(size);
        System.out.println("*********************");
        Integer zhangsan = map.remove("zhangsan");  // 移除key = zhangsan的元素数据,并返回该移除的value值。
        System.out.println(zhangsan);
        System.out.println(map);
        map.clear();  // 清空该Map 集合当中的存储的元素数据
        System.out.println(map.size());
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例

import java.util.HashMap;
import java.util.Map;
public class MapTest {
    public static void main(String[] args) {
        // Map 接口 , HashMap实现类,多态,<String,Integer> 泛型
        Map<String,Integer> map = new HashMap<String,Integer>();
        // 添加元素数据:
        map.put("zhangsan",66);
        map.put("lisi",89);
        Map<String,Integer> map2 = new HashMap<String,Integer>();
        map2.put("wangwu",97);
        map2.put("lihua",99);
        map.putAll(map2);  // 将 map2 集合中所有的key-value键值对添加到此 map集合当中去
                           // 注意:两者集合存储的元素数据类型必须是一致的才可以添加成功。
        System.out.println(map);
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

元素查询的操作:

V get(Object key);  // 获取指定key对应的value
boolean containsKey(Object key);  // 判断该集合当中是否包含指定的 key 值。
boolean containsValue(Object value); // 判断判断该集合当中是否包含指定的 value 值。
boolean isEmpty();  // 判断此集合是否为 空,是返回 true,不是返回 false;
boolean equals(Object o); // 判断当前map和参数对象 o 是否相等

举例:

import java.util.HashMap;
import java.util.Map;
public class MapTest {
    public static void main(String[] args) {
        // Map 接口 , HashMap实现类,多态,<String,Integer> 泛型
        Map<String,Integer> map = new HashMap<String,Integer>();
        // 添加元素数据:
        map.put("zhangsan",66);
        map.put("lisi",89);
        map.put("wangwu",97);
        map.put("lihua",99);
        System.out.println(map.get("zhangsan"));  // 获取到对应 key上的 value值
        System.out.println(map.containsKey("zhangsan"));  // 判断该集合当中是否存在 key = zhangsan的键值对
        System.out.println(map.containsValue(99));  // 判断该集合当中是否存在 value = 99的键值对
        System.out.println(map.isEmpty());  // 判断该集合是否为空
        System.out.println(map.equals(map)); //  判断当前map和参数对象 o 是否相等
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

元视图操作的方法:

Set<K> keySet();  // 返回所有key构成的Set集合
Collection<V> values();  // 返回所有value构成的Collection集合

举例:

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest {
    public static void main(String[] args) {
        // Map 接口 , HashMap实现类,多态,<String,Integer> 泛型
        Map<String,Integer> map = new HashMap<String,Integer>();
        // 添加元素数据:
        map.put("zhangsan",66);
        map.put("lisi",89);
        map.put("wangwu",97);
        map.put("lihua",99);
        Set<String> keys = map.keySet();  // 返回此集合当中所有的 key 值存储到 Set 集合当中
        for (String s : keys) {
            System.out.println(s);
        }
        System.out.println("****************");
        Collection<Integer> values = map.values();  // 返回此集合当中所有的 value 值存储到 Collection 集合当中
        // Collection 接口集合可以使用迭代器
        Iterator<Integer> iterator = values.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Set<Map.Entry<K,V>> entrySet();  // 返回所有key-value对构成的Set集合

其中的 Map.Entry 表示的是一个接口,也可以理解为是一个类。

*   Set<Map.Entry<K,V>> entrySet() 将 Map集合转换成 Set集合
*   假设现在有一个 Map集合 ,如下所示:
*     map1 集合对象
*     key               value
*     1                 zhangsan
*     2                 lisi
*     3                 wangwu
*     4                 zhaoliu
*
*     Set set = mop1.entrySet();
*     set 集合对象
*     1=zhangsan
*     2=lisi
*     3=wangwu
*     4=zhaoliu

Map.Entry<K,V> 的图示:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例:

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest {
    public static void main(String[] args) {
        // Map 接口 , HashMap实现类,多态,<String,Integer> 泛型
        Map<String,Integer> map = new HashMap<String,Integer>();
        // 添加元素数据:
        map.put("zhangsan",66);
        map.put("lisi",89);
        map.put("wangwu",97);
        map.put("lihua",99);
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            // getKey()获取 key 值,getValue()获取value值
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

3. Map实现类之一:HashMap

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明
Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例:

如下是 Set 中的 Key 存储自定义类 Person5 ,其中并没有重写Object 中的 equals() 方法和 hashCode()方法。会出现 Key 存储到重复的数据。

package blogs.blogs7;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Person5,Integer> hashMap = new HashMap<Person5, Integer>();
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("zhangsan",23),4);
        hashMap.put(new Person5("lihua",20),5);
       // 遍历HashMap 集合
        Set<Map.Entry<Person5,Integer>> entries = hashMap.entrySet();
        for (Map.Entry<Person5,Integer> entry : entries) {
            System.out.println(entry);
        }
    }
}
class Person5 {
    String name;
    int age;
    public Person5() {
    }
    public Person5(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person5{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

修改: 重写其中的 Key 值的 Set 集合中存储的 类中的 equals() 和 hashCode() 方法。

package blogs.blogs7;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Person5,Integer> hashMap = new HashMap<Person5, Integer>();
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("Tom",19),1);
        hashMap.put(new Person5("zhangsan",23),4);
        hashMap.put(new Person5("lihua",20),5);
       // 遍历HashMap 集合
        Set<Map.Entry<Person5,Integer>> entries = hashMap.entrySet();
        for (Map.Entry<Person5,Integer> entry : entries) {
            System.out.println(entry);
        }
    }
}
class Person5 {
    String name;
    int age;
    public Person5() {
    }
    public Person5(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person5)) return false;
        Person5 person5 = (Person5) o;
        return age == person5.age &&
                Objects.equals(name, person5.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Person5{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

HashMap中的 Key值可以存储添加 null 值,但是仅仅只能添加一个 null ,因为 Key 中的数据存储在 Set集合当中的,不可重复,而 Value 值也可以存储 null值,而且可以存储多个 null 值,因为 Value 值数据底层是存储在Collection集合当中的

举例:

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class HashMapTest {
    public static void main(String[] args) {
        HashMap<String,Integer> hashMap = new HashMap<String, Integer>();
        hashMap.put(null,null);
        hashMap.put(null,null);
        hashMap.put(null,null);
        hashMap.put("1",null);
        hashMap.put("2",null);
        hashMap.put("3",null);
        // 遍历HashMap 集合
        Set<Map.Entry<String,Integer>> entries = hashMap.entrySet();
        for (Map.Entry<String,Integer> entry : entries) {
            System.out.println(entry);
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

常用方法总结:

3.1 HashMap的存储结构

JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)

JDK 8版本发布以后:HashMap是数组+链表+红黑树实现

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

如下是 JDK8 的HashMap 结构图

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

3.2 HashMap源码中的重要常量

/**
 * The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16  HashMap的默认容量是 16
-----------------------------------------------------------------------------------
 /**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;  // HashMap的最大支持容量,2^30
-----------------------------------------------------------------------------------
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;  // HashMap的默认加载因子
-----------------------------------------------------------------------------------
 /**
* The bin count threshold for using a tree rather than list for a
* bin.  Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8;  // Bucket中链表长度大于该默认值,转化为红黑树
-----------------------------------------------------------------------------------
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6; // Bucket中红黑树存储的Node小于该默认值,转化为链表
-----------------------------------------------------------------------------------
/**
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
*/
static final int MIN_TREEIFY_CAPACITY = 64; // 桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
-----------------------------------------------------------------------------------
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;  // 存储元素的数组,总是2的n次幂
-----------------------------------------------------------------------------------
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/
transient Set<Map.Entry<K,V>> entrySet;  // 存储具体元素的集合
-----------------------------------------------------------------------------------
/**
* The number of key-value mappings contained in this map.
*/
transient int size;  // HashMap中实际存储的键值对的数量
-----------------------------------------------------------------------------------
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash).  This field is used to make iterators on Collection-views of
* the HashMap fail-fast.  (See ConcurrentModificationException).
*/
transient int modCount;  // HashMap扩容和结构改变的次数。
-----------------------------------------------------------------------------------
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold;  // 扩容的临界值,=容量 * 填充因子
-----------------------------------------------------------------------------------
/**
* The load factor for the hash table.
*
* @serial
*/
final float loadFactor;  // 填充因子

3.3 HashMap的存储结构:JDK 1.8之前 / JDK 1.8之后

3.3.1 JDk 1.8 之前

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

3.3.2 JDk 1.8 及之后

JDK8: HashMap 的内部存储结构其实是:数组+链表+树 的结合。当实例化一个 new HashMap 时,会初始化 initilCapacityloadFactor ,在 put() 第一对映射关系(键值对)添加时,系统会创建一个长度为 initilCapacityNode 数组 ,这个长度在哈希表中被称为 ”容量" (Capacity),在这个数组中可以存放元素的位置,我们称之为 “桶”(bucket) ,每个 bucket 都有自己的索引,系统可以根据索引快速的查找 bucket 中的元素。

每个bucket 中存储一个元素数据,既 一个 Node 对象,但每一个 Node 对象可以带一个引用变量 next ,用于指向下一个元素,因此,在一个桶中,就有可能生成一个 Node 链表。也可能是一个一个TreeNode 对象,每一个TreeNode 对象可以有两个叶子节点 leftright ,因此,在一个桶中,就有可能生成一个 TreeNode 树。而新添加的元素作为链表的 last ,或树的叶子节点。

JDK1.8 源码分析:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

3.3.3 JDK8 HashMap 集合添加元素的过程

HashMap 集合中添加 put(key1,value1) 键值对, 首先调用 元素 key1 所在类的 hashCode() 方法,来得到该 key1对象的 hashCode(哈希) 值。

然后再根据得到的 hashCode (哈希)值,通过某种散列函数 计算除该对象在 HashSet 集合中底层Node[] 数组的存储位置(即为:索引下标位置),(这个散列函数会与底层数组的长度相计算得到在数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布,该散列函数设计的越好)。

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

如下是查找图示:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

假设将所有的hashCode()方法返回设定为不一样的值,可以吗?,有什么问题:

不行,因为这样的话,就导致 HashMap 集合底层的哈希表就成为了一维数组了,没有链表的概念了,更没有哈希表的概念了。

假设将所有的hashCode()方法返回设返回值固定为某个值,可以吗?,有什么问题:

答:不可以,设将所有的hashCode()方法,返回值固定为某个值,那么会导致底层哈希表变成了纯单向链表。这种情况下我们称为:散列分别不均匀。

什么时散列分布不均匀

假设我们有 100 个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的,是散列分布均匀的

3.3.4 JDK8 HashMap 进行 "扩容"和 "树形化"

扩容

put(Key1,value1) 添加键值对个数超过 数组大小(数组总大小 length ,不是数组中实际存放的键值对个数 size),时,就会进行数组扩容。loadFactor 的默认值:DEFAULT_LOAD_FACTOR)为0.75,这是一个折中的取值,也就是说,默认情况下,数组大小(DEFAULT_INITIAL_CAPACITY)为16 ,那么当 HashMap 中元素个数超过 16 * 0.75 = 12 (这个值就是代码中的 threshold值,也叫临界值)的时候,就把数组的大小扩展为 2 * 16 = 32 ,即扩大 1倍 ,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作。所以在开发中如果我们可以预估计其存储的数据量,也就是 HashMap中存储元素的个数,那么就调用其HashMap(int num) 设定存储容量的大小,减少扩容次数,提高 HashMap的性能

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

树形化

HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

补充:

关于映射关系的key是否可以修改 ???

answer:不要修改,映射关系存储到 HashMap 中会存储 key哈希值 ,这样就不用每次查找时,重新计算每一个 EntryNode (TreeNode)的 哈希值了,因此如果已经 putMap 中的映射关系,再修改 key 的属性,而这个属性有参与 hashCode值的计算,那么会导致匹配不上。

为什么HashMap扩容时,不是数组满了的时候扩容而是达到一个的 0.75 的额度才扩容 ???

因为HashMap 集合的底层时由 链表 + 数组 + 树 构成的。由于链表的存在,HashMap 当中的数组不一定会存储满了。

以及涉及到 HashMap 集合性能最优的效果,散列均匀分布,所以是到达一定额度 0.75 是最好的情况了.

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

负载因子值的大小,对HashMap有什么影响 ???

/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;  // HashMap的默认加载因子

负载因子的大小决定了HashMap的数据密度。

负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长,

造成查询或插入时的比较次数增多,性能会下降。

负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的

几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间。

按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数。

3.3.5 总结:JDK1.8 相较于之前的变化:

4. Map实现类之二:LinkedHashMap

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

HashMap中的内部类:Node

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

LinkedHashMap中的内部类:Entry

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例:

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class LinkedHashMapTest {
    public static void main(String[] args) {
        // 创建 LinkedHashMap 集合对象
        LinkedHashMap<String,Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
        // 添加元素数据(键值对)
        linkedHashMap.put("lihua",99);
        linkedHashMap.put("zhangsan",89);
        linkedHashMap.put("lisi",79);
        linkedHashMap.put("wangwu",69);
        // 遍历 LinkedHashMap 集合
        // 获取到key-value 存储的 Set Entry 内部类集合对象
        Set<Map.Entry<String, Integer>> entries = linkedHashMap.entrySet();
        // 获取到该 Set Entry 内部类集合的迭代器
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

5. Map实现类之三:TreeMap

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例:

TreeMap 集合中存储自定义类 Person6 对象,其中的 Key 存储的类为自定义 Person6 对象,该对象重写了 equals() 和 hashCode()方法,但是没有重写比较器的情况,报异常:java.lang.ClassCastException 类型转换异常。

将其中的Person6 中 age 年龄,升序排列

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明


import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
    public static void main(String[] args) {
        // 创建TreeMap 集合对象,其中 Key 存储的类为自定义 Person6
        TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>();
        // 添加元素
        treeMap.put(new Person6("lihua",18),99);
        treeMap.put(new Person6("zhangsan",20),89);
        treeMap.put(new Person6("lisi",25),79);
        treeMap.put(new Person6("wangwu",19),69);
        // 遍历集合
        // 遍历 TreeMap 集合
        // 获取到key-value 存储的 Set Entry 内部类集合对象
        Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
        // 获取到该 Set Entry 内部类集合的迭代器
        Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            Map.Entry<Person6, Integer> entry = iterator.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}
class Person6 {
    String name;
    int age;
    public Person6() {
    }
    public Person6(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    // 当对象中的 name 和 age 属性值相同返回 true,否则返回 fasle
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person6)) return false;
        Person6 person6 = (Person6) o;
        return getAge() == person6.getAge() &&
                Objects.equals(getName(), person6.getName());
    }
    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }
    @Override
    public String toString() {
        return "Person6{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

修正: 对 Key 中所存储的类,提供比较器,方式一:自然排序,该存储类实现 java.lang.Comparable接口,并重写其中的 CompareTo()重写方法。


import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
    public static void main(String[] args) {
        // 创建TreeMap 集合对象,其中 Key 存储的类为自定义 Person6
        TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>();
        // 添加元素
        treeMap.put(new Person6("lihua",18),99);
        treeMap.put(new Person6("zhangsan",20),89);
        treeMap.put(new Person6("lisi",25),79);
        treeMap.put(new Person6("wangwu",19),69);
        // 遍历集合
        // 遍历 TreeMap 集合
        // 获取到key-value 存储的 Set Entry 内部类集合对象
        Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
        // 获取到该 Set Entry 内部类集合的迭代器
        Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            Map.Entry<Person6, Integer> entry = iterator.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}
class Person6 implements Comparable<Person6>{
    String name;
    int age;
    public Person6() {
    }
    public Person6(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    // 当对象中的 name 和 age 属性值相同返回 true,否则返回 fasle
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person6)) return false;
        Person6 person6 = (Person6) o;
        return getAge() == person6.getAge() &&
                Objects.equals(getName(), person6.getName());
    }
    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }
    /**
     * 升序的比较规则:
     * this > 参数 ,返回 > 0
     * this < 参数,返回 < 0
     * this == 参数,返回 == 0;
     * 降序反过来:
     * this > 参数 ,返回 < 0
     * this < 参数,返回 > 0
     * this == 参数,返回 == 0;
     */
    @Override
    public int compareTo(Person6 o) {
        // 首先判断该需要比较的参数是否是同一个实例,同一个实例的对象才能比较
        if(o instanceof Person6) {  // 其实这里我们使用了<Person3 o> 泛型限定了,就不需要判断了
            Person6 person6 = (Person6) o;  // 是对应的实例向下转型。
            if(this.age > person6.age) {
                return 1;
            } else if( this.age < person6.age) {
                return -1;
            } else {
                return 0;
            }
        } else {
            // throw 可以替代 return
            throw new RuntimeException("类型不一致");  // 抛出运行时异常
        }
    }
    @Override
    public String toString() {
        return "Person6{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

修改方式二:定制排序 创建 TreeMap 集合对象时,将一个匿名实现Com 的类,作为参数,传递给构造器。该匿名实现类定制排序按照你 Perso6 中的 age 年龄降序排列

public TreeMap(Comparator<? super K> comparator); // 构造一个新的,空的树图,按照给定的比较器排序。
package blogs.blogs7;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
    public static void main(String[] args) {
        // 创建一个 TreeMap 集合对象,将匿名实现的比较器(定制排序),作为参数,传递给构造器
        TreeMap<Person6,Integer> treeMap = new TreeMap<Person6,Integer>(new Comparator<Person6>() {
            @Override
            public int compare(Person6 o1, Person6 o2) {
                // 判断是否是对应比较的实例,其实这里我们可以不用判断的,因为使用的泛型限定
                if(o1 instanceof Person6 && o2 instanceof  Person6) {
                    Person6 p1 = (Person6)o1;
                    Person6 p2 = (Person6)o2;  // 向下转型为对应的实例对象,从而获取比较属性
                    if(p1.age > p2.age) {
                        return -1;
                    } else if(p1.age < p2.age) {
                        return 1;
                    } else {
                        return 0;
                    }
                }
                // throw 可以代替 return
                throw new RuntimeException("类型不一致");  // 抛出运行时异常
            }
        });
        // 添加元素
        treeMap.put(new Person6("lihua",18),99);
        treeMap.put(new Person6("zhangsan",20),89);
        treeMap.put(new Person6("lisi",25),79);
        treeMap.put(new Person6("wangwu",19),69);
        // 遍历集合
        // 遍历 TreeMap 集合
        // 获取到key-value 存储的 Set Entry 内部类集合对象
        Set<Map.Entry<Person6, Integer>> entries = treeMap.entrySet();
        // 获取到该 Set Entry 内部类集合的迭代器
        Iterator<Map.Entry<Person6, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            Map.Entry<Person6, Integer> entry = iterator.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}
class Person6 implements Comparable<Person6>{
    String name;
    int age;
    public Person6() {
    }
    public Person6(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    // 当对象中的 name 和 age 属性值相同返回 true,否则返回 fasle
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person6)) return false;
        Person6 person6 = (Person6) o;
        return getAge() == person6.getAge() &&
                Objects.equals(getName(), person6.getName());
    }
    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }
    @Override
    public String toString() {
        return "Person6{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

6. Map实现类之四:Hashtable

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

HashMap和HashTable的比较:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashtableTest {
    public static void main(String[] args) {
        Hashtable<String,Integer> hashtable = new Hashtable<String,Integer>();
        hashtable.put("lihua",1);
        hashtable.put("zhangsan",2);
        hashtable.put("lisi",3);
        hashtable.put("wangwu",4);
        Set<Map.Entry<String, Integer>> entries = hashtable.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

7. Map实现类之五:Properties

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

public Object setProperty(String key,String value); // 致电Hashtable方法put 。 提供与getProperty方法的并行性 。 强制使用字符串的属性键和值。 返回的值是Hashtable调用put的结果。简单的说:就是向Property 集合中添加键值对元素。
public String getProperty(String key); // 通过 key 找到对应的 value值,如果没有找到返回 null

举例:

首先我们先在项目中(注意添加到顶级项目中也就是如下的Test 项目下,不是Test2,或者 day模块下 ,不然无法读取到)添加一个属性文件(以.properties后缀的配置文件)用于Properties 集合读取,内容如下:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

name=Tom
password=abc123
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
    public static void main(String[] args) {
        // Properties 集合常用来处理配置文件:key 和 value 都是String类型
        Properties properties = new Properties();
        try {
            // IO流读取文件信息,需要异常处理
            FileInputStream fileInputStream = new FileInputStream("jdbc.properties"); // 文件名
            properties.load(fileInputStream);  // 加载流对应的文件,同样需要异常处理
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String name = properties.getProperty("name");
        String password = properties.getProperty("password");  // 根据对应文件中的 key 值获取到对应的value值
        System.out.println(name);
        System.out.println(password);
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

8. Map 接口下的集合遍历方式

Map 接口下的集合的遍历方式:注意:Map 集合中没有下标可以访问的。也没有迭代器可以使用的。

方式一: 普遍使用,二次取值。通过获取 keySet() 方法获取到 Map 集合中所有的 key 值,返回一个 Set 集合。再通过遍历 Set 集合中存储的所有的 key ,使用 get(key) 方法获取到对应的 value值。

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Traverse {
    // Map 集合遍历方式一:
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "value1");
        map.put("2", "value2");
        map.put("3", "value3");
        // 1.获取到该 Map 集合当中的所有 Key 值
        Set<String> keys = map.keySet();
        // 2.遍历所有的 key 值
        for (String key : keys) {
            // 3. 通过 key 获取到对应的 value 值
            System.out.println(key + "--->" + map.get(key));
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

方式二: 通过使用 entrySet() 方法,返回一个:Set< Map.Entry<K, V> > 集合对象, 再通过获取到该 Set<Map.Entry> 集合 的迭代器,通过迭代器遍历,获取到Map.Entry中存储的 key(getKey()), value(getVale()) 方法

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
    // Map 集合遍历方式二:
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "value1");
        map.put("2", "value2");
        map.put("3", "value3");
        // 1. 获取到 Set<Map.Entry> 集合对象
        Set<Map.Entry<String, String>> entries = map.entrySet();
        // 2. 获取到该 Set<Map.Entry> 集合 的迭代器
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        // 3. 通过迭代器遍历,获取到Map.Entry中存储的 key,value值
        while(iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

方式三: 推荐,尤其是容量大时。因为这是一次性获取到 Map 中所有的key-value 值后,再取出的,效率高

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
    // Map 集合遍历方式三:
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "value1");
        map.put("2", "value2");
        map.put("3", "value3");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

方式四: 通过Map.values() 返回一个Collection 集合遍历所有的value,但不能遍历key

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Traverse {
    // Map集合遍历方式四:
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "value1");
        map.put("2", "value2");
        map.put("3", "value3");
        // 获取到集合当中所有的 value值
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

9. Collections工具类

一个独立的集合 工具类

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

9.1 Collections常用方法

排序:

public static void reverse(List<?> list);  // 反转 List 中元素的顺序
public static void shuffle(List<?> list);  // 对 List 集合元素进行随机排序
public static <T extends Comparable<? super T>> void sort(List<T> list);  // 根据元素的自然顺序对指定 List 集合元素按升序排序
public static <T> void sort(List<T> list,Comparator<? super T> c);  // 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
public static void swap(List<?> list,int i,int j);  // 将指定 list 集合中的 i 处元素和 j 处元素进行交换

查找,替换

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);  // 根据元素的自然顺序,返回给定集合中的最大元素
public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp);  // 根据 Comparator 指定的顺序,返回给定集合中的最大元素
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll); // 根据元素的自然顺序,返回给定集合中的最小元素。
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp);  // 根据Comparator 指定的顺序,返回给定集合中的最小元素。
public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal); // 用新值替换List 对象的所有旧值.
public static int frequency(Collection<?> c,Object o);  // 返回指定集合中指定元素的出现次数
public static <T> void copy(List<? super T> dest,List<? extends T> src); // 将 src 集合中的内容复制到 dest 集合当中

注意该 copy(List dest,List src) 方法,两个集合对象存储的数据类型是必须是一样的,不然无法拷贝添加到 dest 集合当中的。

还有拷贝存储到的对象 dest 的 size()长度 < 被拷贝的 src 的 size()长度 就会拷贝失败,报异常: IndexOutOfBoundsException

所以拷贝存储到的对象 dest 的 size()长度 必须 >= 被拷贝的 src 的 size()长度注意是 size()实际存储元素数据的长度,不是length()集合的长度

如下源码:

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

举例 : 解决思路如下:

package blogs.blogs7;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsTest {
    public static void main(String[] args) {
        List<Integer> src = new ArrayList<Integer>();
        src.add(1);
        src.add(99);
        src.add(-1);
        src.add(66);
        // 创建一个 和 src 集合存储类型一样的  Arrays.asList(new Integer[src.size()])数组,并设置该数组的大小长度为 src.size()
        // 再使用这个数组创建拷贝存储的 desc 集合对象,默认数组没有添加数据(这里的是 null)
        // 这样就 desc 就拥有了一个和 sec集合一样大小的 size()长度了。
        List<Integer> desc = new ArrayList<Integer>();
        desc = Arrays.asList(new Integer[src.size()]);
        for (Integer integer : desc) {
            System.out.println(integer);
        }
        // copy()拷贝
        Collections.copy(desc, src);
        System.out.println("***********  拷贝  ************");
        for (Integer num : desc) {
            System.out.println(num);
        }
    }
}

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

10. 总结:

补充 :各个集合的转换,可以使用对应的方法,或构造器

	@Test
    public void test2() {
        Set<String> set = new HashSet<>();
        set.add("king");
        set.add("kingsoft");
        set.add("king2");
        set.add("king1");
        // 将Set集合转换成List集合
        List<String> myList = new ArrayList<>(set);
        for(String s : myList) {
            System.out.println(s);
        }
    }

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

11. 最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见!!!
Java集合  Map 集合 与 操作集合的工具类: Collections 的详细说明

发表回复