HashMap和HashTable的区别

HashMap和HashTable都采用了hash法进行索引,他们有以下区别:

  1. HashMap是HashTable的轻量级实现,是非线程安全的,它是根据键的hash值存取数据,具有很快的访问速度。HashMap和HashTable都实现了Map接口。但是HashMap的key和value可以为空,HashTable不允许key,value为空。如果HashTable的key或value为空,则抛出空指针异常。
  2. HashMap中没有contains()方法。HashMap和HashTable中有containsKey()和containsValue()方法。HashTable有contains()方法,这个contains()方法指的是包含value。
  3. HashTable是线程安全的,HashMap不是线程安全的。多个线程访问HashMap时候需要对HashMap同步。而HashTable不需要。
  4. HashMap和HashTable采用的hash/rehash算法都几乎一样,性能不会有很大差异。
  5. HashMap中hash数组默认大小是16。HashTable中hash数组默认大小是11,增加方式是old*2+1
  6. Hash值得使用不同,HashTable直接使用对象的hashCode

 

HashMap中添加元素和查找元素的原理:

HashMap中添加键值对<key,value>的过程如下:

首先调用key的hashCode()方法生成一个hash值h1:

  1. 如果这个hash值h1在HashMap中不存在,则直接将这个<key,value>值添加进HashMap
  2. 如果这个hash值h1存在,那么找出hash值为h1的所有的key,调用key的equals()方法,判断当前的key和已经存在的key是否相同,如果相同equals()返回true,说明有相同的key的键值对存在,那么直接覆盖key对应的value;如果不同equals()方法返回false,说明要添加的键值对在HashMap中不存在,那么,那么添加这个键值对进去。当新增加的key的hash值已经在HashMap中存在就会产生冲突,处理冲突方式有开放地址法,再hash法,链地址法等。

HashMap中通过key查找value过程:

首先调用key的hashCode()方法,获取到key对应的hash值h1,这样就可以确定键为key的所有的值存储的首地址,如果h1对应的key值有多个,那么程序会遍历所有的key,通过调用key的equals()方法来判断key的内容是否相等。相等则返回key对应的value,没找到返回null;

 

看看下面的例子:

例子1:

package com.experiment.xjtuse;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Test1 {
	public static void main(String[] args) {
		HashMap<String, String> map=new HashMap<String, String>();
		map.put("a", "bbb");
		map.put("b", "ggg");
		map.put("a", "ccc");
		Iterator it=map.entrySet().iterator();
		while(it.hasNext()){
			Map.Entry entry=(Map.Entry)it.next();
			String key=(String)entry.getKey();
			String value=(String)entry.getValue();
			System.out.println("key:"+key+"   value:"+value);
		}
	}
}

输出结果为:

key:b   value:ggg
key:a   value:ccc

例子2:

package com.experiment.xjtuse;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

class Person{
	String id;
	String name;
	public Person(String id,String name){
		this.id=id;
		this.name=name;
	}
	public String toString(){
		return "id:"+this.id+" name:"+this.name;
	}
}
public class Test2 {
	public static void main(String[] args) {
		HashMap<Person, String> map=new HashMap<Person, String>();
		map.put(new Person("111", "彭召"), "666");
		map.put(new Person("111", "彭召"), "666");
		map.put(new Person("222", "小丁"), "222");
		Iterator it=map.entrySet().iterator();
		while(it.hasNext()){
			Map.Entry entry=(Map.Entry)it.next();
			Person p1=(Person) entry.getKey();
			String s1=(String)entry.getValue();
			System.out.println(p1.toString()+"   "+s1);
		}
	}
}

输出结果为:

id:111 name:彭召   666
id:111 name:彭召   666
id:222 name:小丁   222

 

 

例子3:

package com.experiment.xjtuse;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

class Person0{
	String id;
	String name;
	public Person0(String id,String name){
		this.id=id;
		this.name=name;
	}
	public String toString(){
		return "id:"+this.id+" name:"+this.name;
	}
	public int hashCode(){
		return id.hashCode();
	}
	public boolean equals(Object o){
		Person0 p=(Person0)o;
		return p.id.equals(this.id);
	}
}

public class Test3 {
	public static void main(String[] args) {
		HashMap<Person0, String> map=new HashMap<Person0, String>();
		map.put(new Person0("111", "彭召"), "666");
		map.put(new Person0("111", "彭召"), "666");
		map.put(new Person0("222", "小丁"), "222");
		Iterator it=map.entrySet().iterator();
		while(it.hasNext()){
			Map.Entry entry=(Map.Entry)it.next();
			Person0 p1=(Person0) entry.getKey();
			String s1=(String)entry.getValue();
			System.out.println(p1.toString()+"   "+s1);
		}

	}
}

输出结果为:

id:222 name:小丁   222
id:111 name:彭召   666

这里例子1中String类中重写了hashCode()和equals()方法,而例子2中没有重写这两个方法,默认调用继承的Object类的这两个方法。而Object的hashCode()方法返回的是对象在内存中的首地址,由于两个person对象在内存的堆中的不同位置保存,因此首地址不同,返回的hashcode不同,而它的equals()方法是看着两个对象是不是同一个对象,是的话返回true,否则返回false。因此两个对象hashcode不同会被插入到HashMap不同的地方。如果想根据id相同就认为是同一个person则要重写这两个方法。就像例子3那样。

一般来说,重写了equals()方法就必须重写hashCode方法,如果两个对象相等,那么他们一定有相同的hashCode,但是如果两个对象的hashCode相等,他们不一定是相等的对象。

 

 

 

 

 

HashMapHashtable 都是用于存储键值对的数据结构,它们在功能上非常相似,但也存在一些区别。 1. 线程安全性:Hashtable 是线程安全的,即多个线程可以同时访问一个 Hashtable 实例而不需要额外的同步措施。而 HashMap 不是线程安全的,如果多个线程同时访问一个 HashMap 实例,可能会导致数据不一致的问题。如果需要在多线程环境下使用,可以考虑使用 ConcurrentHashMap。 2. null 键和 null 值:Hashtable 不允许键或值为 null,如果尝试将 null 键或 null 值放入 Hashtable 中,会抛出 NullPointerException。而 HashMap 允许键和值为 null,可以正常存储和获取 null 值。 3. 继承关系:Hashtable 是 Dictionary 类的子类,而 HashMap 是 AbstractMap 类的子类。由于继承关系的不同,导致它们在实现上有一些差异。 4. 迭代顺序:HashMap 不保证迭代顺序,即遍历 HashMap 的键值对时,不一定按照插入顺序或者其他顺序进行遍历。而 Hashtable 的迭代顺序是按照插入顺序进行的。 5. 性能:由于 Hashtable 是线程安全的,它在多线程环境下的性能可能会受到一定影响。而 HashMap 在单线程环境下的性能通常会更好。 总的来说,如果在单线程环境下使用,并且需要允许键或值为 null,可以优先选择使用 HashMap。如果在多线程环境下使用,或者需要保证迭代顺序,可以考虑使用 Hashtable
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值