Java教程

EighteenDay-java Map及其实现类HashMap、Hashtable

本文主要是介绍EighteenDay-java Map及其实现类HashMap、Hashtable,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、Map<k,v>接口的常用方法

  V put(K key, V value) 添加键值对

  void clear() 清除所有键值对

  boolean containsKey(Object key) 是否包含指定键 是就返回true

  boolean containsValue(Object value) 是否包含指定值 是就返回true

  V get(Object key) 以键找值 返回值

  boolean isEmpty() 此地图是否包含键值对 不包含返回true

  Set<K> keySet() 获取所有的键 以set集合形式返回

  V remove(Object key) 以键删除键值对

  int size() 此地图中含有多少个键值对

  Set<Map.Entry<K,V>> entrySet() 把Map转换成Set集合

    Map: 1:zhangsan 2:lisi 3:wangwu

    Set: 1=zhangsan 2=lisi 3=wangwu [它们的类型是Map.Entry<k,v>]

public static void main(String[] args) {
    //创建Map集合对象
    Map<Integer,String> map=new HashMap<>();
    //添加键值对
    map.put(1,"zhangsan");
    map.put(2,"wangwu");
    map.put(3,"lisi");
    map.put(4,"liuliu");
    //Map中键值对的个数
    System.out.println(map.size());//4
    //以键找值
    System.out.println(map.get(1));//zhangsan
    //包含键
    System.out.println(map.containsKey(3));//true
    //包含值
    System.out.println(map.containsValue("zhangsan"));//true
    //删除键值对
    String v=map.remove(2);
    System.out.println(v);//wangwu
    //是否为空
    System.out.println(map.isEmpty());//false
    //返回所有键
    Set<Integer> ints = map.keySet();
    for (Integer anInt : ints) {
        System.out.print(anInt+" ");//1 3 4
    }

2、有关Map取键值对

键值对的第一种获取方式:先获取所有的键,在获取值

第二种方式 把键值对一起取出来(效率较高)

public static void main(String[] args) {
    Map<Integer,String> map=new HashMap<>();
    map.put(1,"wo");
    map.put(2,"hao");
    map.put(3,"ni");
    //键值对的第一种获取方式:先获取所有的键,在获取值
    //获取所有键
    Set<Integer> keys = map.keySet();
   /* //迭代器
   Iterator<Integer> k= keys.iterator();
   //迭代
    while(k.hasNext()){
        Integer k1 = k.next();
        System.out.println(k1+":"+map.get(k1));
    }
    */
    //foreach
    for (Integer key : keys) {
        System.out.print(key+":"+map.get(key)+" ");//1:wo 2:hao 3:ni
​
    }
    System.out.println();
    //第二种方式 把键值对一起取出来
    Set<Map.Entry<Integer, String>> set = map.entrySet();
    for (Map.Entry<Integer, String> node: set) {
        System.out.print(node.getKey()+":"+node.getValue()+" ");//1:wo 2:hao 3:ni
    }
​
}

3、HashMap

  1>、HsahMap集合底层是哈希表/散列表的数据结构

  2>、哈希表是一个数组和单向列表的结合体

    数组在查询方面效率很高,链表在增删方面效率很高

  3>、HsahMap底层源代码

//HashMap底层实际上是一个一维数组
Node<k,v>[] table;
//静态内部类HashMap.Node
static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;//哈希值,是key的hashCode()方法执行结果。hash值通过算法函数,可以转换成地址
    final K key;//存储到Map集合中的key
    V value;//存储到Map集合中的Value
    Node<K,V> next;//下一个节点的内存地址
  }

哈希表/散列表:一维数组,这个数组中的每一个元素都是一个单向链表

4、HashMap集合的存取原理

Map中的put(k,v)方法原理:

接收k,v后,封装到Node<k,v>对象中,调用k的hashCode()方法,得到K的哈希值,通过哈希函数与算法生成数组下标值,找到对应的数组下标位置,若为空,则直接把键值对放进去,若不为空,则一一比较在此数组下标 位置上的链表的k值,使用equals,返回true则把v值用新的覆盖,返回false,则把此键值对放在链表的末尾

Map中的get(k)方法原理:

接收到k值后 底层调用hashCode方法,得到k的哈希值后通过哈希函数和算法生成数组下标,通过数组下标快速定位到链表在数组中的位置,若此位置为null则返回null,若不为空,拿k与单链表一一比较通过equals ,返回true则拿出k对应的v值,返回false 则返回null。

综上知,若要自定义引用类型,使用集合,一定要重写equals和hashCode方法。

如果hashCode返回的值只有一个,则此哈希表为纯链表,属于不均匀散列表

分布均匀散列表:有100个元素,数组空间为10,则每个空间有10个;

如果hashCode返回值每次都返回不一样的值,则哈希表为纯数组,属于不均匀散列表

重点:HashMap集合的默认初始化容量是16,默认因子是0.75 默认因子:当HashMap底层数组的容量达到75%的时候,数组开始扩 容,HashMap 集合的初始化容量必须是2的倍数,因为为了达到散列 均匀,调高HashMap集合的存取效率

如图所示

(图为B站老师所画)

 

 

HashMap集合的key特点

无序不可重复:

无序:因为不一定挂到那个链表上

不可重复:equals保证了key不会重复

*JDK8之后在哈希表中当单向链表超过8个,则数据结构会变为红黑树结构,当红黑树节点小于6时又变回链表

5、Hashtable

Hashtable可以为空吗?

  Hashtable的键与值都不可以为null

  HashMap的键与值可以为null

Hashtable方法都带有synchronized:线程安全的。线程安全有其他方案,这个Hashtable对线程的处理效率较低,运用较少了。

底层都是哈希表,初始化容量是11,默认加载容量0.75f,扩容是原容量乘以2加1.

public static void main(String[] args) {
    Map map=new Hashtable();
    map.put(null,100);//NullPointerException异常
    System.out.println(map.size());
}

6、Properties

Properties属性类对象的相关方法:

   Properties是Map的一个集合,继承Hashtable

  Properties的key与value都是String类型的

   Properties被称为属性类对象

//存
properties.setProperty("url","jdbc:mysql://localhost:3306/product");
//取
String url = properties.getProperty("url");      
System.out.println(url);//jdbc:mysql://localhost:3306/product

7、TreeSet

  1>、TreeSet集合无序不重复,但可以按大小排序,底层是TreeMap

  2>、TreeMap的底层是二叉树

  3>、TreeSet存储数据相当于在TreeMap的key里存储

  4>对于自定义类型来说,可以排序吗?

  无法排序,因为没有指定排序规则 会出现ClassCastException异常:class EighteenDay.student cannot be cast to class java.lang.Comparable

  在底层代码中,HashMap的put方法会进行键的比较(compareTo()方法),键值在比较前会强制转换成Comparable比较器类型,而student为自定义类型 没有实现比较器接口,故无  法转型,报错。

  总结:在使用TreeSet/TreeMap集合存储自定义类型数据时,自定义类一定要继承Java.lang.Comparable,重写compareTo方法进行排序规则的制定

 

public static void main(String[] args) {
  student st=new student(13);
  student st2=new student(12);
  TreeSet<student> ts=new TreeSet<>();
  ts.add(st);
  ts.add(st2);
  System.out.println(ts.size());
  for (student t : ts) {
    System.out.println(t);
  }
}

class student implements Comparable<student>{
  int age;

  public student(int age) {
    this.age = age;
  }
//重写compareTo 制定排序规则
  @Override
  public int compareTo(student o) {
    return this.age-o.age;//这个是降序 o.age-this.age 就顺序相反了(升序)
  /*底层代码以二叉树的形式排序,我们需要在这里重写compareTo返回三种情况的某一种,负数,0,正数
  cmp = k.compareTo(t.key);
  if (cmp < 0)
  t = t.left;
  else if (cmp > 0)
  t = t.right;
  else
  return t.setValue(value);
  */
  }
  //重写toString方法
  @Override
  public String toString() {
    return "age=" + age;
  }
}

这篇关于EighteenDay-java Map及其实现类HashMap、Hashtable的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!