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>

效果如下:
Java笔记十二.常用API-Hashtable类及其与HashMap、HashSet的区别_第1张图片
注释:在上面的这个程序中,我们定义了一个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) 类似
  • Methods inherited from class java.util.Hashtable

    clear, clone, compute, computeIfAbsent, computeIfPresent, contains, containsKey, containsValue, elements, entrySet, equals, forEach, get,getOrDefault, hashCode, isEmpty, keys, keySet, merge, put, putAll, putIfAbsent, rehash, remove, remove, replace, replace, replaceAll, size,toString, values
  • Methods inherited from class java.lang.Object

    finalize, getClass, notify, notifyAll, wait, wait, wait
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>

效果演示:
Java笔记十二.常用API-Hashtable类及其与HashMap、HashSet的区别_第2张图片


总结一: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;  
    } 

参考:
http://docs.oracle.com/javase/8/docs/api/index.html
http://blog.csdn.net/zwjlpeng/article/details/9746425
http://blog.csdn.net/wl_ldy/article/details/5941770

你可能感兴趣的:(java)