Java笔记十二.常用API-Hashtable类及其与HashMap、HashSet的区别

常用API-Hashtable类及其与HashMap、HashSet的区别
转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)

一、Hashtable<K,V>类
1.概述
    Hashtable是一种高级数据结构,实现了一个Key-Value映射的哈希表,用以快速检索数据。Hashtable不仅可以像Vector一样动态存储一系列的对象,而且对存储的每一个值对象(值)都安排与另一个键对象(关键字)相关联,非null对象都可以被使用作为键对象或者值对象。为了能够成功从hashtable中存储和读取对象元素,实现键对象的类必须实现hashCode方法和equals方法。
2.Hashtable类API
(1)继承关系:java.lang.Object <----  java.util.Dictionary<K,V> <----- java.util.Hashtable<K,V>
(2)构造方法
Hashtable()
Constructs a new, empty hashtable with a default initial capacity (11) and load factor (0.75).
Hashtable(int initialCapacity)
Constructs a new, empty hashtable with the specified initial capacity and default load factor (0.75).
Hashtable(int initialCapacity, float loadFactor)
Constructs a new, empty hashtable with the specified initial capacity and the specified load factor.
Hashtable(Map<? extends K,? extends V> t)
Constructs a new hashtable with the same mappings as the given Map.
(3)常用方法
boolean contains(Object value):检索hashtable表中是否有一些键映射到指定的值对象
boolean containsKey(Object key)检索hashtable表中是否包含指定的键对象
boolean containsValue(Object value):返回true,如果这个hashtable中一个或多个键映射到这个值
Enumeration<V> elements():返回hashtable所有的元素到一个Emumeration对象
V get(Object key):返回键对应所映射的值对象,如果集合中不存在这样的映射则返回null
boolean equals(Object o):比较指定的对象是否存在于Map集合中
int hashCode():计算哈希值
Enumeration<K> keys():将hashtable所有的键值返回为一个Emumeration对象
V put(K key, V value) :将一个键值对映射添加到hashtable中
 replace(K key, V value) :如果该映射存在,替代
Collection<V> values() :返回存储结构中的所有值对象,返回类型为Collection类型
int size() :返回hashtable中键对象的个数
3.Hashtable类应用技巧
(1)如何向Hashtable对象中存储数据?
    在Hashtable应用中使用Hashtable.put(Object key,Object value)方法存储数据;从Hashtable中检索数据,使用Hashtable.get(Object key)方法。值和关键字都可以是任何类型的非空的对象(?)
实例源码:设计一个存储数字的Hashtable,应英文数字作为关键字
<span style="font-size:18px;">Hashtable<String, Integer> numbers=new Hashtable<String, Integer>();
numbers.put("one",new Integer(1));    //向Hashtable数据结构中存储一个数据(为键值对)
          numbers.put("two",new Integer(2)); 
          numbers.put("three",new Integer(3)); 
          Integer n=(Integer)numbers.get("two");//检索"two"关键字对应的数据,其中 numbers.get("two")返回Object类型值对象
          if(n!=null)
          {
                System.in.println("two = "+n);
          }</span>

(2)为何需覆盖Object.hashCode方法和Object.equals方法?
    由于作为key的对象通过计算其散列函数确定与之对应的value的位置,因此任何为key的对象都必须实现hasCode和equals方法。hasCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
 实例源码:编写一个类(MyKey.java)用于关键字,即这个类要实现equals和hashCode方法。
 
<span style="font-size:18px;">class  MyKey
{
     private String name;
     private int age;  
    //1.构造函数:赋初值。其中this.name等价于MyKey的对象.name(调用私有变量并给其赋值)
    public MyKey(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    //2.重写toString方法:实现指定的功能-返回一个值为非空的String对象
    public String toString()
    {
        return new String(name + ","+age);
    }
    //3.实现equals方法:当名字和年龄都一致时,可以判定为同一对象(Object obj)或者说要检索的键存在Hashtable存储结构中(如果存在返回true)
    public boolean equals(Object obj)
    {
        MyKey mykey1=this;
        MyKey mykey2=(MyKey)obj;    
        if(mykey1.name.equals(mykey2.name) && mykey2.age==mykey1.age)    //其中obj为需要检索的对象
            return true;
         else
            return false;
    }
    //4.哈希函数:确定Key对象与之对应Value的存储位置,相同对象的哈希值一定相同否者就会出现冲突
    public int hashCode()
    {
        return name.hashCode()+age;
    }
}  </span><span style="font-size:14px;">  </span>

注释:当我们通过指定键对象检索Hashtable数据结构中是否包含该key-value键值对时,在重写equals方法中,需要定义两个MyKey对象, MyKey mykey1=this为Hashtable表中固有的键对象;MyKey mykey2=(MyKey)obj-由于Hashtable的get方法返回的是Object对象,所以我们需要将其转换为MyKey对象,然后再与前者进行变量比较然后再确定是否为同一目标。
4.实例源码:实现一个Hashtable数据结构,然后向其存储数据然后在进行检索。如果两个人名字和年龄都相同,我们就认为他们是同一个人。
 HashtableTest.java(键对象的值---值对象的值)
 
<span style="font-size:18px;">import java.util.*;
public class HashtableTest
{
    public static void main(String[] args)
    {
        //1.构造一个Hashtable对象,即建立一个Hashtable并向其添加元素(key-value键值对)
        Hashtable<MyKey, Integer> numbers=new Hashtable<MyKey, Integer>();                                
        numbers.put(new MyKey("zhangsan",20),new Integer(1));//添加key-value键值对到结构中
        numbers.put(new MyKey("lisi",18),new Integer(2));
        numbers.put(new MyKey("wangwu",23),new Integer(3));
        //2.使用Enumeration获取所有键对象并进行遍历
        Enumeration<MyKey> e=numbers.keys();               //numbers.keys()返回hashtable中所有键对象元素
        while(e.hasMoreElements())                        //遍历每一元素的键对象
        {
            MyKey key=(MyKey)e.nextElement();   //e.nextElement返回的是一个Object对象
            System.out.print(key.toString()+"=");    //打印键对象的值,其中toString作用是打印指定的内容
            System.out.println(numbers.get(key).toString());//打印Hashtable中键对象对应值对象的值,其中toSting的作用是将值对象的值转换为字符串输出
        }
    }
}</span>

效果如下:

注释:在上面的这个程序中,我们定义了一个Hashtable的对象numbers,然后给他放入了3个MyKey类对象和对应的阿拉伯数字。最后,我们在假装不知道该对象里面的值的情况下。利用Emumeration接口的对象e将值和关键字一一对应地取出来

二、Properties类
1.概述
 Properties是Hashtable的子类,与Hashtable的主要区别是Properties增加了将Hashtable对象中的关键字-值(key-value)对保存到文件(输入流)和从文件中读取关键字-值(key-value)对到Hashtable对象中的方法。Properties主要要用于应用程序的选项设置,即程序退出时将功能/设置值存储到文件,程序启动时将功能-设置值读到了内存,然后程序按新的设置运行。有一点需要注意的是,Properties数据结构的属性列表中的每个键及其对应的值是一个字符串,多线程安全。
2.Properties类API
(1)继承关系:java.lang.Object <----  java.util.Dictionary<K,V> <----- java.util.Hashtable<K,V> <---java.util.Properties
(2)构造方法
Properties() Creates an empty property list with no default values.
Properties(Properties defaults) Creates an empty property list with the specified defaults.
注释:defaults-属性列表包含一些对应于任何键值的默认值,这些键值不存在于属性列表中
(3)常用方法
String getProperty(String key) :检索该属性列表中属性的指定键对象
Object setProperty(String key, String value) :相当与调用Hashtable的put方法,即向属性数据结构中添加键值对
void load(InputStream inStream) :从输入字节流读取属性列表(一系列键值对)
    void load(Reader reader) 、void loadFromXML(InputStream in) 类似
void store(OutputStream out, String comments) :将Properties表中的属性列表(一系列键值对)到文件流
    void store(Writer writer, String comments) 、void storeToXML(OutputStream os, String comment) 类似
3.Properties类应用技巧
(1)程序选项属性的设置与读取、存储
     如果用到Properties类的store方法进行存储每个属性的关键字和值都必须是字符串类型的,所以上面的程序没有用从父类Hashtable继承到的put、get方法进行属性的设置与读取,而是直接用了Properties类的setProperty、getProperty方法进行属性的设置与读取实现从文件读取设置属性、存储设置属性到文件中,有三种情况:
a. load(Reader) / store(Writer, String):一般情况
b.load(InputStream) / store(OutputStream, String):当字符编码为 ISO 8859-1
c. loadFromXML(InputStream) and storeToXML(OutputStream, String, String):字符编码为UTF-8/UTF-16,文件类型为XML
(2)实例源码
    编写一个程序,当程序每次启动时都去读取一个记录文件,直接读取文件中所记录的运行次数并加1后,有重新将新的运行次数存回文件。
<span style="font-size:18px;">import java.util.*;
import java.io.*;
class PropertiesTest {
 public static void main(String[] args)
 {
  Properties settings=new Properties();
 //1.加载一个文件流,如果该文件不存在则表示打开的次数count=0
  try
  {
   settings.load(new FileInputStream("C:\\count.txt"));	//从文件中读取属性列表(为一系列键值对)到Properties结构中
  }
  catch(Exception e)
  {
   settings.setProperty("Count", new Integer(0).toString());//向Properties结构中存储键值对key-value
  }
 //2.次数累加并将其保存到count.txt文件中
  int c=Integer.parseInt(settings.getProperty("Count"))+1;	//获取键对象对应值对象的内容,并累加1(程序被打开一次)
  System.out.println("这是本程序第"+c+"次被使用");
  settings.put("Count", new Integer(c).toString());	 //再次向Properties结构存储新的键值对
  try
  {
   settings.store(new FileOutputStream("C:\\count.txt"), "This Program is used:");/*将Properties所有属性列表(所有键值对)保存到文件中*/
  }
  catch(Exception e)
  {
   System.out.println(e.getMessage());
  }
 }
}</span>

效果演示:




总结一:HashMap与HashTable的区别?

        HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例,具体区别如下:
1.Hashtable是基于Dictionary类的,而HashMap是基于Map接口的一个实现 
2.Hashtable里默认的方法是同步的,而HashMap则是非同步的,因此Hashtable是多线程安全的,HashMap未经同步所以在多线程诚和要动手同步,使用以下语句对HashMap进行同步操作。
                            Map m = Collections.synchronizedMap(new HashMap(...));
3.HashMap可以将空值作为一个表的条目的key或者value,HashMap中由于键不能重复,因此只有一条记录的Key可以是空值,而value可以有多个为空,但HashTable不允许null值(键与值均不行
4.内存初始大小不同,HashTable初始大小是11,而HashMap初始大小是16 
5.内存扩容时采取的方式也不同,Hashtable采用的是2*old+1,而HashMap是2*old。 
6.哈希值的计算方法不同,Hashtable直接使用的是对象的hashCode,而HashMap则是在对象的hashCode的基础上还进行了一些变化
nt hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:
int hash = hash(k);
int i = indexFor(hash, table.length);
static int hash(Object x) {
  h ^= (h >>> 20) ^ (h >>> 12);
     return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
  return h & (length-1);
}
7.HashTable使用Enumeration进行遍历,HashMap使用Iterator进行遍历
HashTable的遍历:
Hashtable ht=new Hashtable();
        ht.put("1", "111");
        ht.put("3","333");
        ht.put("2", "222");
        Enumeration en=ht.keys();
        while(en.hasMoreElements())
       {
            Object key=en.nextElement();
            Object value=ht.get(key);
            System.out.println("key="+key+",value="+value);
        }  

总结二:HashMap与HashSet的区别?

1. HashMap可以看作三个视图:Key的Set(不可重复),value的Collection(可重复且无序),Entry(链表)的Set,HashMap为散列映射,它是基于hash table的一个实现,它可在常量时间内安插元素,或找出一组key-value
    HashSet为散列集,其底层采用的是HashMap进行实现的,但是没有key-value(即它不需要Key和Value两个值),只有HashMap的key-set的视图,HashSet不容许重复的对象。
        public HashSet() {  
                        map = new HashMap<E,Object>();  
                 }  
2. 调用HashSet的add方法时,实际上是向HashMap中增加了一行(key-value对),该行的key就是向HashSet增加的哪个对象,该行的value就是一个Object类型的常量
private static final Object PRESENT = new Object();  
public boolean add(E e) {  
    return map.put(e, PRESENT)==null;  
    }  
public boolean remove(Object o) {  
    return map.remove(o)==PRESENT;  
    } 

参考:
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值