Map

  java.util.Map,接口,映射结构,无序,key不可重复,常用的实现类有HashTable、HashMap、ConcurrentHashMap。

===========================================

  HashMap非线程安全,用哈希表存放键值对,处理冲突的方法类似链地址法。内部类Node实现了Map接口的内部接口Entry,是一个单链表结点结构,有key,value,next属性。内部建立一个Node数组table,初始长度为16,实际长度也可以自己指定。
  
  put(key, value)内部过程,根据key通过int hash = hash(key.hashCode())计算出一个哈希值,通过int index = hash % 表长得到一个0到表长-1的整数,判断数组table下标index处的值。若无,根据key、value创建一个Note对象存入该位置。若有,将key与当前Note的key对比,若相同,根据key不可重复,用value替换当前Note的value;若不同,根据当前Note的next,找到下一个Note继续比较,其中key相同的操作同上,不同的继续,直到next为null,此时创建新的Note对象,使用头插法插入新的结点。
  
  get(key)内部过程,根据key通过如上过程生成table下标,并到下标处比较key。若相同,返回对应的value;若不同,根据next继续,直到next为null,此时返回null。
  
  HashMap要求key不可重复,插入元素时,内部有一个key的比较过程,其使用equals方法。该方法是基类Object的方法,默认实现对比的是对象的引用,必须要重写key所属类型的equals方法,保证比较的是对象的某个值而不是引用。
  散列的定义是,相同对象的hashCode必须相同,不同对象的hashCode不一定,相同后就为冲突。hashCode是基类Object的方法,其为native本地方法,取决于平台,java本身并没有具体的实现,默认使用对象的引用生成。重写equals后,不同引用对象的内容可能相同,被认为是相同对象,由此重写equals后必须重写hashCode,如以对象内某一不变的属性的hashCode返回值作为重写的哈希值。
  String的equals与hashCode都已经被重写为根据字符串的内容作比较,而不是引用,由此通常使用String类型作为key。需要注意的是,在重写对象的hashCode时,必须以该对象的某个不会被改变的属性为基准,否则对象的属性改变,hashCode值也会改变,会出现前后不一致的现象。

  HashMap的扩容机制为,当哈希表的长度不够时,要对其进行扩大。最大长度为2的30次方,扩充因子为0.75f,指当哈希表中元素个数>=哈希表当前长度 * 0.75f时,会自动将表长度扩大为当前表长的一倍。每次扩容都要重新计算表内已存元素的位置,必然会增加算法的复杂性,在定义new对象时尽量不要使用默认的长度16,而是指定一个我们认为合适的大小。

===========================================

  HashTable线程安全,结构基本同HashMap。
  HashMap是新框架的内容,建议使用;HashTable是旧框架的内容,不推荐使用。
  HashMap非线程安全,但可以通过Collection的静态方法synchronizedMap方法实现线程安全;HashTable线程安全。
  HashMap允许空值,key,value均可;HashTable不允许空值,key,value均不可。
  HashMap哈希地址hash的生成不是直接使用hashCode,而是对hashCode进行了封装,key为空时,不会调用hashCode方法,而是直接存在索引index为0的位置,key为null的元素均存在哈希表数组下标为0的位置,由于key不可重复,所有的键值对中只可能有一个key为null的键值对,但是可以有多个value为null的键值对;HashTable哈希地址hash的生成直接使用hashCode。
  综上推荐使用HashMap。

===========================================

  ConcurrentHashMap对HashMap的改进,HashMap为非线程安全,并发环境下要给整个HashMap加锁,会明显降低效率。ConcurrentHashMap将HashMap分成若干段,每段为一个子HashMap,并分段上锁。线程对每个段的访问是线程安全的,但多个段之间是可以并发的。避免HashMap上锁后,整个不可用的现象。
  上锁指资源一旦加锁,仅对其加锁的线程可访问,即使该线程当前不占用处理器,仍占有资源,直到其使用完才可释放。

===========================================

// Map.Entry
Map<String, Object> map = new HashMap<String, Object>();

// 不使用Entry遍历
// 将Map中的key转为集合
Set<String> keys = map.keySet();
Iterator iterator = keys.iterator();

// 遍历迭代器
while(iterator.hasNext()) {
    String key = iterator.next();
    // 遍历Map
    Object value = map.get(key);
}


// 使用Entry遍历,Entry为Map接口的内部接口,也是键值对类型
// 将Map内的键值对转为集合
Set<Entry> entries = map.entrySet();
Iterator iterator = entries.iterator();

// 遍历迭代器
while(iterator.hasNext()) {
    Entry entry = iterator.next();
    // 直接从Entry内取出key与value
    String key = entry.getKey();
    Object value = entry.getValue();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值