欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java核心技术-集合-映射

程序员文章站 2022-05-13 20:04:27
...

一 基本映射操作

1 映射用来存放键/值对

2 映射提供了两种通用的实现:HashMapTreeMap,两个类都实现了Map接口

    散列映射对键进行散列;树映射用键的整体顺序对元素进行排序,并将其组织成搜索树

    散列或比较函数只能作用于键,与键关联的值不能进行散列或比较

3应该如何选择散列或者树?与集合一样,散列的速度稍快一些,如果不需要按照排列顺序访问键,就最好选择散列。

     

   Map<String,Employee> staff = new HashMap<>();//HashMap implements Map

        Employee harry = new Employee("tiffany");

        staff.put("3245", harry);

 

在这里键是一个字符串,对应的值是Employee对象。要想检索一个对象,必须使用一个键。

        String id = "3245";

        e = staff.get(id)

 

 如果在映射中没有与给定键对应的信息,get就返回null

5 键必须是唯一的,不能对同一个键存放两个值。如果对同一个键两次调用put方法,第二个值就会取代第一个值。

6 用forEach迭代处理映射的键和值,例

staff.forEach((k,v)->

        System.out.println("key"+k+",value="+v));

Map类常用方法:

V get(Object key):获取与键对应的值或对象

default V getOrDefault(Object key,V defaultValue):获取与键关联的值或对象

V put(K key,V value):将键与对应得到值关系插入到映射中

。。。

二 更新映射项

1 如何处理更新映射项时键第一次出现的情况:

  •  

        counts.put(word,counts.getOrDefault(word,0)+1);
    
        counts,putIfAbsent(word,0);
    
        counts.put(word,counts.get(word)+1);
    
        counts.merge(word,1,Integer::sum);//将把word与1关联,否则使用Integer::sum函数组合原值和1

     

  •  

三 映射视图

1 三种视图:键集,值集合,键/值对集

  •  

    Set<K> keySet()
    
    Collection<V> values()
    
    Set<Map.Entry<K,V>> entrySet()

     

这三种方法会分别返回这3个视图,其中keySet既不是HashSet也不是TreeSet,而是实现了Set接口的另外某个类的对象。Set接口扩展了Collection接口,因此可以像使用集合一样使用keySet

例1:

Set<String> keys = map.keySet();

for(String key:keys){

//可以枚举一个映射的所有键

}

例2:同时查看键和值:

for(Map.Entry<String,Employee> entry:staff.entry.entrySet()){

String k = entry.getKey();

Employee v = entry.getValue();

}

四 弱散列映射

1 垃圾回收器跟踪活动的对象,只要映射对象是活动的,其中的所有桶也是活动的,它们不能被回收。所以需要由程序负责从长期存活的映射表中删除那些无用的值,或者使用WeakHashMap类

2 WeakHashMap使用弱引用来保存键,WeakHashMap对象将引用保存到另外一个对象(散列键)中

3 通常,如果垃圾回收器发现某个特定的对象已经没有他人引用了,就将其回收。但对于只能由WeakReference引用的对象,垃圾回收器仍然要回收它,但是要将引用这个对象的弱引用放入队列中。WeakHashMap将周期性地检查队列,以便找出新添加的弱引用,然后将其删除

五 链接散列集和映射

1 为了避免在散列表中的项从表面上看起来是随机排列的,可以使用LinkedHashSet和LinkedHashMap类来记住插入元素项的顺序。

例:        

Map<String,Employee> staff = new LinkedHashMap<>();

        staff.put("1234", new Employee("tiffany"));

        staff.put("2345", new Employee("sarah"));

        staff.put("1345", new Employee("jeff"));

        staff.put("3345", new Employee("jelly"));

        Set<String> keys = staff.keySet();

        for (String key : keys) {

            System.out.println(key);

        }

        for (Employee e : staff.values()) {

            System.out.println(e.getName());

        }

2 链接散列映射将用访问顺序,而不是插入顺序,对映射条目进行迭代。

3 可以使用LinkedHashMap来实现访问顺序这一目的:将访问频率高的元素放到内存中,而访问频率低的元素从数据库中读取

可以构造一个LinkedHashMap的子类,然后覆盖下面的方法

protected boolean removeEldestEntry(Map.Entry<K,V> eldest)

六 枚举集与映射

1.EnumSet是一个枚举类型元素集的高效实现。

2.EnumMap是一个键类型为枚举类型的映射。

七 标识散列映射(IdentityHashMap类)

在这个类中,键的散列值不是用hashCode 函数实现计算的,而是用System.identityHashCode方法计算的

在进行对象的比较时,使用的是== ,而不是equals,故比较的是对象

补充:==和equals的区别:

==比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作

equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。

例题:

public class test1 {

   public static void main(String[] args) {

     String a = new String("ab"); // a 为一个引用 
     String b = new String("ab"); // b为另一个引用,对象的内容一样 
     String aa = "ab"; // 放在常量池中

    String bb = "ab"; // 从常量池中查找 

  if     (aa == bb) // true 

     System.out.println("aa==bb");

  if (a == b) // false,非同一对象

     System.out.println("a==b");

     if (a.equals(b)) // true

     System.out.println("aEQb");

     if (42 == 42.0) { // true

     System.out.println("true");

     }

     }

    }