java集合——映射表+专用集合映射表类

【0】README

0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java集合——映射表+专用集合映射表类 的相关知识;
0.2) for full source code , please visit https://github.com/pacosonTang/core-java-volume/blob/master/chapter13/MapTest.java + https://github.com/pacosonTang/core-java-volume/blob/master/chapter13/MapTestOne.java + https://github.com/pacosonTang/core-java-volume/blob/master/chapter13/EnumSetAndEnumMapTest.java


【1】 映射表(键值对——HashMap + TreeMap)

1.1)映射表: 通常,我们知道某些键的信息, 想要查找与之对应的元素, 映射表就是为此目的而设计的;(键值对)

  • 1.1.1)java类为映射表提供了两个通用的实现: HashMap 和 TreeMap, 它们都实现了 Map 接口;
  • 1.1.2)散列映射表对键进行散列, 树映射表用键的整体顺序对元素进行排序,并将其组织成搜索树;
  • 1.1.3)散列或 比较函数只能作用于键。 与键关联的值不能进行散列或比较;(只与key有关, 与value 无关);

1.2)应该选择 散列映射还是树映射表呢? 如果不需要按照排列顺序访问键, 就最好选择散列;(TreeMap 有序, 而HashMap无序)

  • 1.2.1)看个荔枝:
Map<String, Employee> staff = new HashMap<>(); // HashMap implements Map
Employee harry = new Employee();
staff.puf("hehe", harry);

对以上代码的分析(Analysis):

  • A1)要检索一个对象,提供一个键:
String s = "hehe";
e = staff.get(s) ; //gets harry
  • 如果在 映射表中没有与给定键对应的信息, get 将返回 null;
  • A2) remove方法用于从映射表中删除给定键的对应元素, 而 size 用户返回映射表的元素数目;

1.3)获得映射表的视图 (干货)

  • 1.3.1)映射表有3个视图:键集、值集 和 键值对集。键集和键值集对形成了一个集合,因为在映射表中一个键只能有一个副本。
  • 1.3.2)下面方法将返回 3个 视图:
Set<K> keySet();
Collection<K> values();
Set<Map.Entry<K,V>> entrySet

Attention)

  • A1) keySet 既不是 HashSet 也不是 TreeSet, 而是实现了 Set 接口的某个其他类的对象;
  • A2) Set接口扩展了 Collection接口, 因此,可以与使用任何集合一样使用 keySet;

  • 1.3.3)看个荔枝:

Set<String> keys =  map.keySet();
for(String key : keys)
{
    do sth with key
}

Hint)

  • H1)如果想要查看键和值, 就可以通过枚举 各个条目查看,以避免对值进行查找。可以使用下面的代码框架:
for(Map.Entry<String , Employee> entry: staff.entrySet())
{
    String key = entry.getKey();
    Employee e = entry.getValue();
    do sth with key
}
  • H2)如果调用迭代器的 remvoe方法, 实际上就从映射表中删除了 键以及对应的值。 但是, 不能将元素添加到 键集的视图中KeySet;如果试图调用add 方法, 将会抛出一个 UnsupportedOperationException异常;

1.4)看个荔枝:
这里写图片描述

API java.util.Map<K, V> 1.2
V get(OBject key)
V put(K key, V value)
void putAll(Map<? extends K, ? extends V> entries)
boolean containsKey(Object key)
boolean containsValue(Object value)
Set<Map.Entry<K,v> entrySet>
Set<K> keySet()
Collection><V> values();

API java.util.Map.Entry<K, V> 1.2
K getKey()
V getValue()
V setValue(V newValue)

API java.util.HashMap<K, V> 1.2
HashMap()
HashMap(int initialCapacity)
HashMap(int initialCapacity, flaot loadFactor)

API java.util.TreeMap<K, V> 1.2
TreeMap(Comparator<? super K> c)
TreeMap(Map<? super K, ? extends V> entries)
TreeMap(SortedMap<? extends K, ? extends V> entries)

API java.util.SortedMap<K, V> 1.2
Comparator<? super K> comparator()
K firstKey()
K lastKey()

【2】专用集合映射表类

2.1)弱散列映射表(WeakHashMap)

  • 2.1.1)出现的问题: 设计 WeakHashMap 类是为了解决一个有趣的问题。 如果有一个值, 对应的键已经不再使用了,将会出现什么情况呢?假定对某个键的最后一次引用已经消亡, 不再有任何途径引用这个值的对象了。 但是,由于在程序中的任何部分没有再出现这个键, 所以,这个键值对无法从映射表中删除。 为什么垃圾回收器不能删除它呢? 难道删除无用的对象不是垃圾回收器的工作吗?
  • 2.1.2)垃圾回收器: 它跟踪活动的对象, 只要映射表对象是活动的, 其中的所有桶都是活动的, 它们不能被回收。
  • 2.1.3)因此,需要由程序负责从长期存活的映射表中删除那些无用的值。或者使用 WeakHashMap 完成这件事情。
  • 2.1.4)当对键的唯一引用来自散列条目时, 这一数据结构与垃圾回收器协同工作一起删除键值对;

2.2)了解 WeakHashMap的内部运行情况: WeakHashMap 使用 弱引用(weak reference)保存键。

  • WeakReference对象将引用保存到另外一个对象中, 在这里,就是散列表键。对于这种类型的对象,垃圾回收器用一种特有的方式进行处理。 通常,如果垃圾回收器发现这个特定的对象已经没有他人引用了,就将其回收。然而, 如果某个对象只能由 WeakReference 引用, 垃圾回收器仍然会回收它, 但要将引用这个对象的弱引用放入队列中。 WeakHashMap 将周期性地检查队列, 以便找出新添加的弱引用。 一个弱引用进入队列意味着这个键不再被他人使用, 并且已经被收集起来。于是 , WeakHashMap 将删除对应的条目;

2.3)链接散列集和链接映射表(LinkedHashSet 和 LinkedHashMap)

  • 2.3.1)Java SE 1.4 增加了两个类: LinkedHashSet 和 LinkedHashMap, 用来记住插入元素项的顺序(干货——引入链接散列集和链接散列表的原因, LinkedHashSet 和 LinkedHashMap, 用来记住插入元素项的顺序), 这样就可以避免在散列表中的项从表面上看是随机排列的。当条目插入到表中时,就会并入到双向链表中;
  • 2.3.2)看个荔枝:
    这里写图片描述
Map<String, Employee> staff = new HashMap<>();
      staff.put("14", new Employee("Amy"));
      staff.put("56", new Employee("Harry"));
      staff.put("15", new Employee("Gary"));
      staff.put("45", new Employee("Francesca"));
  • 然后 staff.keySet().iterator() 以下面次序枚举键:
    https://github.com/pacosonTang/core-java-volume/blob/master/chapter13/MapTestOne.java
    并且 staff.values().iterator() 以下列顺序枚举这些值;

  • 2.3.3)链接散列映射表将用访问顺序,而不是插入顺序, 对映射表条目进行迭代。每次调用 get 或 put, 受到影响的条目将从当前位置删除, 并放到条目链表的尾部;

  • 2.3.4)访问顺序对于实现高速缓存的 “最近最少使用”原则十分重要。
  • 2.3.5)可以构造一个 LinkedHashMap的子类, 然后覆盖下面这个方法:
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
  • 2.3.6)看个荔枝:(每当方法返回true时, 就添加一个新条目, 从而导致删除 eldest 条目), 下面的高速缓存可以存放100个元素:
Map<K, V> cache = new LinkedhashMap<>(128, 0.75F, true)
{
    protecte boolean removeEldestEntry(Map.Entry<K, V> eldest)
    {
        return size() > 100;
    }
}

2.4)枚举集与映射表

  • 2.4.1) EnumSet 是一个枚举类型元素集的高效实现。 如果对应的值在集合中, 相应的位被置为1;
  • 2.4.2) EnumSet 类没有公共的构造器。 可以使用静态工厂方法构造这个集;
enum Weekday {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, , SATURDAY, SUNDAY}
EnumSet<Weekday> always = EnumSet.allOf(Weekday.class);
EnumSet<Weekday> never = EnumSet.noneof(Weekday.class);
EnumSet<Weekday> workday= EnumSet.range(Weekday.MONDAY, Weekday.FRIDAY);
EnumSet<Weekday> mwf = EnumSet.of(Weekday.MONDAY, Weekday.WEDNESDAY, Weekday.FRIDAY);

这里写图片描述

  • 2.4.3)可以修改 Set接口的常用方法来修改 EnumSet;
  • 2.4.4)EnumMap 是一个键类型为 枚举类型的映射表。 它可以直接且高效地用一个值数组实现, 在使用时, 需要再构造器中指定键类型:
EnumMap<Weekday, Employee> map = new EnumMap<>(Weekday.class);

Annotation) 在 EnumSet的 API文档中, 将会看到 E extends Enum , 简单的说, 它的意思是 E 是一个枚举类型。 所有的枚举类型都扩展于 泛型 Enum 类;如 Weekday 扩展于 Enum;
这里写图片描述

API java.util.EnumSet<E extends Enum<E>> 5.0

static <E extends Enum<E>> EnumSet<E> allOf(Class<E> enumType)
返回一个包含给定枚举类型的所有值的集合;

static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> enumType)
返回一个空集, 并有足够的空间保存给定的枚举类型所有的值;

static <E extends Enum<E>> EnumSet<E> range(E from , E to)
返回一个包含 from~to 之间的所有值(包括边界fromto)的集;

static <E extends Enum<E>> EnumSet<E> of(E value)
static <E extends Enum<E>> EnumSet<E> of(E value, E ...values)
返回包括给定值的集合;

API java.util.EnumMap<K extends Enum<K, V>> 5.0
EnumMap<Class<K> keyType>
构造一个键为给定类型的 空映射集;

java.util.IdentityHashMap<K, V> 1.4
IdentityHashMap()
IdentityHashMap(int expectedMaxSize)
构造一个空的标识散列映射集,其容量大于1.5 * expectedMaxSize的2 的最小次幂( expectedMaxSize 的默认值为21)

API java.lang.System 1.0
 static int idnetityHashCode(Object obj) 1.1
返回 Object.hashCode 计算出来的相同散列码, 即使 obj 所属的类已经重新定义了了 hashCode 方法也是如此;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值