当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:17:00  来源:本站整理

java的hashtable的用法[Java编程]

赞助商链接



  本文“java的hashtable的用法[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
Vector答应我们用一个数字从一系列对象中作出挑选,所以它实际是将数字同对象关联起来了.但假定我们想按照其他尺度挑选一系列对象呢?仓库就是这样的一个例子:它的挑选尺度是“最后压入仓库的东西”.这种“从一系列对象中挑选”的概念亦可叫作一个“映射”、“字典”大概“关联数组”.从概念上讲,它看起来象一个Vector,但却不是通过数字来查找对象,而是用另一个对象来查找它们!这普通都属于一个程序中的重要进程.
在Java中,这个概念具体反映到抽象类Dictionary身上.该类的接口是非常直观的size()奉告我们此中包含了多少元素;isEmpty()判断能否包含了元素(是则为true);put(Object key, Object value)增添一个值(我们但愿的东西),并将其同一个键关联起来(想用于搜索它的东西);get(Object key)得到与某个键对应的值;而remove(Object Key)用于从列表中删除“键-值”对.还可以利用列举技术:keys()产生对键的一个列举(Enumeration);而elements()产生对全部值的一个列举.这就是一个Dictionary(字典)的全部.
Dictionary的实现历程并不麻烦.下面列出一种简单的办法,它利用了两个Vector,一个用于包容键,另一个用来包容值:
//: AssocArray.java
// Simple version of a Dictionary
import java.util.*;

public class AssocArray extends Dictionary {
  private Vector keys = new Vector();
  private Vector values = new Vector();
  public int size() { return keys.size(); }
  public boolean isEmpty() {
    return keys.isEmpty();
  }
  public Object put(Object key, Object value) {
    keys.addElement(key);
    values.addElement(value);
    return key;
  }
  public Object get(Object key) {
    int index = keys.indexOf(key);
    // indexOf() Returns -1 if key not found:
    if(index == -1) return null;
    return values.elementAt(index);
  }
  public Object remove(Object key) {
    int index = keys.indexOf(key);
    if(index == -1) return null;
    keys.removeElementAt(index);
    Object returnval = values.elementAt(index);
    values.removeElementAt(index);
    return returnval;
  }
  public Enumeration keys() {
    return keys.elements();
  }
  public Enumeration elements() {
    return values.elements();
  }
  // Test it:
  public static void main(String[] args) {
    AssocArray aa = new AssocArray();
    for(char c = 'a'; c <= 'z'; c++)
      aa.put(String.valueOf(c),
             String.valueOf(c)
             .toUpperCase());
    char[] ca = { 'a', 'e', 'i', 'o', 'u' };
    for(int i = 0; i < ca.length; i++)
      System.out.println("Uppercase: " +
             aa.get(String.valueOf(ca[i])));
  }
} ///:~

在对AssocArray的定义中,我们注意到的第一个问题是它“扩大”了字典.这意味着AssocArray属于Dictionary的一种范例,所以可对其发出与Dictionary一样的恳求.假如想生成自己的Dictionary,并且就在这里举行,那么要做的全部事情只是填充位于Dictionary内的全部办法(并且必须覆盖全部办法,因为它们——除构建器外——都是抽象的).
Vector key和value通过一个尺度索引编号链接起来.也就是说,假如用“roof”的一个键以及“blue”的一个值调用put()——假定我们预备将一个屋子的各部份与它们的油漆颜色关联起来,并且AssocArray里已有100个元素,那么“roof”就会有101个键元素,而“blue”有101个值元素.并且要注意一下get(),假定我们作为键传送“roof”,它就会产生与keys.index.Of()的索引编号,然后用那个索引编号生成相关的值矢量内的值.
main()中举行的测试是非常简单的;它只是将小写字符转换成大写字符,这明显可用更有效的方法举行.但它向我们揭暴露了AssocArray的强盛功效.
尺度Java库只包含Dictionary的一个变种,名为Hashtable(散列表,注释③).Java的散列表具有与AssocArray相同的接口(因为二者都是从Dictionary担当来的).但有一个方面却反映出了差别:履行效率.若细心想想必须为一个get()做的事情,就会发目前一个Vector里搜索键的速度要慢得多.但此时用散列表却可以加快不少速度.没必要用冗长的线性搜索技术来查找一个键,而是用一个特别的值,名为“散列码”.散列码可以获得对象中的信息,然后将其转换成那个对象“相对唯一”的整数(int).全部对象都有一个散列码,而hashCode()是根类Object的一个办法.Hashtable获得对象的hashCode(),然后用它快速查找键.这样可以使性能得到大幅度晋升(④).散列表的具体工作原理已超越了本书的范围(⑤)——大家只需求知道散列表是一种快速的“字典”(Dictionary)便可,而字典是一种非常有效的工具.

③:如筹划利用RMI(在第15章详述),应注意将远程对象置入散列表时会碰到一个问题(参阅《Core Java》,作者Conrell和Horstmann,Prentice-Hall 1997年出版)
④:如这种速度的晋升仍旧不能满意你对性能的要求,乃至可以编写自己的散列表例程,从而进一步加快表格的检索历程.这样做可避免在与Object之间举行造型的时间耽搁,也可以避开由Java类库散列表例程内建的同步历程.
⑤:我的知道的最佳参考读物是《Practical Algorithms for Programmers》,作者为Andrew Binstock和John Rex,Addison-Wesley 1995年出版.

作为利用散列表的一个例子,可考虑用一个程序来查验Java的Math.random()办法的随机性到底若何.在抱负情形下,它应当产生一系列完善的随机分布数字.但为了考证这一点,我们需求生成数目众多的随机数字,然后计算落在差别范围内的数字多少.散列表可以极大简化这一工作,因为它能将对象同对象关联起来(此时是将Math.random()生成的值同那些值呈现的次数关联起来).以下所示:
//: Statistics.java
// Simple demonstration of Hashtable
import java.util.*;

class Counter { 
  int i = 1; 
  public String toString() { 
    return Integer.toString(i); 
  }
}

class Statistics {
  public static void main(String[] args) {
    Hashtable ht = new Hashtable();
    for(int i = 0; i < 10000; i++) {
      // Produce a number between 0 and 20:
      Integer r = 
        new Integer((int)(Math.random() * 20));
      if(ht.containsKey(r))
        ((Counter)ht.get(r)).i++;
      else
        ht.put(r, new Counter());
    }
    System.out.println(ht);
  }
} ///:~

在main()中,每次产生一个随机数字,它城市封装到一个Integer对象里,使句柄可以伴随散列表一同利用(不可对一个调集利用基本数据范例,只能利用对象句柄).containKey()办法查抄这个键能否已经在调集里(也就是说,那个数字从前发现过吗?)若已在调集里,则get()办法得到那个键关联的值,此时是一个Counter(计数器)对象.计数器内的值i随后会增添1,表明这个特定的随机数字又呈现了一次.
假定键从前还没有发现过,那么办法put()仍旧会在散列表内置入一个新的“键-值”对.在成立之初,Counter会自己的变量i自动初始化为1,它标志着该随机数字的第一次呈现.
为显示散列表,只需把它简单地打印出来便可.Hashtable toString()办法能遍历全部键-值对,并为每一对都调用toString().Integer toString()是事前定义好的,可看到计数器利用的toString.一次运行的后果(增添了一些换行)以下:
{19=526, 18=533, 17=460, 16=513, 15=521, 14=495,
 13=512, 12=483, 11=488, 10=487, 9=514, 8=523,
 7=497, 6=487, 5=480, 4=489, 3=509, 2=503, 1=475,
 0=505}
大家大概会对Counter类能否必要感到迷惑,它看起来仿佛根本没有封装类Integer的功效.为什么不用int或Integer呢?事实上,由于全部调集能包容的唯一对象句柄,所以根本不可以利用整数.学过调集后,封装类的概念对大家来说便大概更简单理解了,因为不可以将任何基本数据范例置入调集里.但是,我们对Java封装器能做的唯一事情就是将其初始化成一个特定的值,然后读取那个值.也就是说,一旦封装器对象已经成立,就没有办法改变一个值.这使得Integer封装器对办理我们的问题毫无意义,所以不得不成立一个新类,用它来满意自己的要求.

1. 成立“关键”类
在前面的例子里,我们用一个尺度库的类(Integer)作为Hashtable的一个键利用.作为一个键,它能很好地工作,因为它已经具有精确运行的全部条件.但在利用散列表的时刻,一旦我们成立自己的类作为键利用,就会碰到一个很常见的问题.比方,假定一套天色预报系统将Groundhog(土拔鼠)对象匹配成Prediction(预报).这看起来非常直观:我们成立两个类,然后将Groundhog作为键利用,而将Prediction作为值利用.以下所示:
//: SpringDetector.java
// Looks plausible, but doesn't work right.
import java.util.*;

class Groundhog {
  int ghNumber;
  Groundhog(int n) { ghNumber = n; }
}

class Prediction {
  boolean shadow = Math.random() > 0.5;
  public String toString() {
    if(shadow)
      return "Six more weeks of Winter!";
    else
      return "Early Spring!";
  }
}

public class SpringDetector {
  public static void main(String[] args) {
    Hashtable ht = new Hashtable();
    for(int i = 0; i < 10; i++)
      ht.put(new Groundhog(i), new Prediction());
    System.out.println("ht = " + ht + "\n");
    System.out.println(
      "Looking up prediction for groundhog #3:");
    Groundhog gh = new Groundhog(3);
    if(ht.containsKey(gh))
      System.out.println((Prediction)ht.get(gh));
  }
} ///:~
每个Groundhog都具有一个标识号码,所以赤了在散列表中查找一个Prediction,只需指导它“奉告我与Groundhog号码3相关的Prediction”.Prediction类包含了一个布尔值,用Math.random()举行初始化,以及一个toString()为我们注释后果.在main()中,用Groundhog以及与它们相关的Prediction填充一个散列表.散列表被打印出来,以便我们看到它们确切已被填充.随后,用标识号码为3的一个Groundhog查找与Groundhog #3对应的预报.
看起来仿佛非常简单,但实际是不可行的.问题在于Groundhog是从通用的Object根类担当的(若当初未指定底子类,则全部类终究都是从Object担当的).事实上是用Object的hashCode()办法生成每个对象的散列码,并且默许情形下只利用它的对象的地址.所以,Groundhog(3)的第一个实例并不会产生与Groundhog(3)第二个实例相等的散列码,而我们用第二个实例举行检索.
大家大概认为此时要做的全部事情就是精确地覆盖hashCode().但这样做仍然行不能,除非再做另一件事情:覆盖也属于Object一部份的equals().当散列表试图判断我们的键能否等于表内的某个键时,就会用到这个办法.一样地,默许的Object.equals()只是简单地对比对象地址,所以一个Groundhog(3)并不等于另一个Groundhog(3).
因此,为了在散列表中将自己的类作为键利用,必须同时覆盖hashCode()和equals(),就象下面展示的那样:
//: SpringDetector2.java
// If you create a class that's used as a key in
// a Hashtable, you must override hashCode()
// and equals().
import java.util.*;

class Groundhog2 {
  int ghNumber;
  Groundhog2(int n) { ghNumber = n; }
  public int hashCode() { return ghNumber; }
  public boolean equals(Object o) {
    return (o instanceof Groundhog2)
      && (ghNumber == ((Groundhog2)o).ghNumber);
  }
}

public class SpringDetector2 {
  public static void main(String[] args) {
    Hashtable ht = new Hashtable();
    for(int i = 0; i < 10; i++)
      ht.put(new Groundhog2(i),new Prediction());
    System.out.println("ht = " + ht + "\n");
    System.out.println(
      "Looking up prediction for groundhog #3:");
    Groundhog2 gh = new Groundhog2(3);
    if(ht.containsKey(gh))
      System.out.println((Prediction)ht.get(gh));
  }
} ///:~
注意这段代码利用了来自前一个例子的Prediction,所以SpringDetector.java必须首先编译,不然就会在试图编译SpringDetector2.java时得到一个编译期错误.
Groundhog2.hashCode()将土拔鼠号码作为一个标识符返回(在这个例子中,程序员需求保证没有两个土拔鼠用一样的ID号码并存).为了返回一个举世无双的标识符,并不需求hashCode(),equals()办法必须可以严峻判断两个对象能否相等.
equals()办法要举行两种查抄:查抄对象能否为null;若不为null,则持续查抄能否为Groundhog2的一个实例(要用到instanceof关键字,第11章会详加阐述).即便为了持续履行equals(),它也应当是一个Groundhog2.正如大家看到的那样,这种对比成立在实际ghNumber的底子上.这一次一旦我们运路程序,就会看到它终于产生了精确的输出(很多Java库的类都覆盖了hashcode()和equals()办法,以便与自己供应的内容适应).

2. 属性:Hashtable的一种范例
在本书的第一个例子中,我们利用了一个名为Properties(属性)的Hashtable范例.在那个例子中,下述程序行:
Properties p = System.getProperties();
p.list(System.out);
调用了一个名为getProperties()的static办法,用于得到一个特别的Properties对象,对系统的某些特点举行描写.list()属于Properties的一个办法,可将内容发给我们挑选的任何流式输出.也有一个save()办法,可用它将属性列表写入一个文件,以便日后用load()办法读取.
固然Properties类是从Hashtable担当的,但它也包含了一个散列表,用于包容“默许”属性的列表.所以假定没有在主列表里找到一个属性,就会自动搜索默许属性.
Properties类亦可在我们的程序中利用(第17章的ClassScanner.java就是一例).在Java库的用户文档中,常常可以找到更多、更具体的阐明.
  以上是“java的hashtable的用法[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • 利用Javascript实现网页水印(非图片水印)
  • Java开辟环境的搭建
  • Ubuntu java安装与配置
  • 办理Ubuntu 10.04 Firefox3.6 Java浏览器插件不工作的问
  • Ubuntu重装后Java环境的设置
  • Sun Java进入Ubuntu 10.10软件中央
  • Ubuntu 10.10配置Java开辟环境
  • 在Ubuntu 10.10中配置Java环境变量的办法
  • Ubuntu下Java环境的搭建
  • Ubuntu 10.04 下安装 Java, JRE
  • Ubuntu 10.04下的搭建SUN JAVA开辟环境
  • Ubuntu 12.04安装java7
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .