Java类库是Java语言提供的已经实现的标准类的集合,是Java语言的API,利用这些类库可以方便快速的实现程序中的各种功能。本章具体讲述了语言包java.lang和实用程序包java.util中常用的数学运算类、字符串类、日期时间以及向量哈希表等类的使用方法。
****************************************************************
Java基础类库
Java 的类库是 Java 语言提供的已经实现的标准类的集合,是 Java 编程的 API(Application Program Interface),它可以帮助开发者方便、快捷地开发 Java 程序。这些类根据实现的功能不同,可以划分为不同的集合,每个集合组成一个包,称为类库。Java 类库中大部分都是由Sun 公司提供的,这些类库称为基础类库。
Java 语言中提供了大量的类库共程序开发者来使用,了解类库的结构可以帮助开发者节省大量的编程时间,而且能够使编写的程序更简单更实用。Java 中丰富的类库资源也是 Java 语言的一大特色,是 Java 程序设计的基础。
Java 常用包的简单介绍如下:
- java.lang 包:主要含有与语言相关的类。java.lang 包由解释程序自动加载,不需要显示说明。
- java.io 包:主要含有与输入/输出相关的类,这些类提供了对不同的输入和输出设备读写数据的支持,这些输入和输出设备包括键盘、显示器、打印机、磁盘文件等。
- java.util 包:包括许多具有特定功能的类,有日期、向量、哈希表、堆栈等,其中 Date类支持与时间有关的操作。
- java.swing 包和 java.awt 包:提供了创建图形用户界面元素的类。通过这些元素,编程者可以控制所写的 Applet 或 Application 的外观界面。包中包含了窗口、对话框、菜单等类。
- java.net 包:含有与网络操作相关的类,如 TCP Scokets、URL 等工具。
- java.applet 包:含有控制 HTML 文档格式、应用程序中的声音等资源的类,其中 Applet类是用来创建包含于 HTML 的 Applet 必不可少的类。
- java.beans 包:定义了应用程序编程接口(API),Java Beans 是 Java 应用程序环境的中性平台组件结构。
*****************************************************************
Java Object类
java.lang 包中定义的 Object 类是所有 Java 类的根父类,其中定义了一些实现和支持面向对象机制的重要方法。任何 Java 对象,如果没有父类,就默认它继承了 Object 类。 因此, 实际上,以前的定义是下面的简略:public class Employee extends Object
public class Manager extends Employee
Object 类定义许多有用的方法,由于是根类,这些方法在其他类中都存在,一般是进行了重载或覆盖,实现了各自的具体功能。
equals方法
Object 类定义的 equals 方法用于判别某个指定的对象与当前对象(调用 equals 方法的对象)是否等价。 在 Java 语言中数据等价的基本含义是指两个数据的值相等。在equals和“==”进行比较的时候,引用类型数据比较的是引用,即内存地址,基本数据类型比较的是值。
注意:
- equals()方法只能比较引用类型,“==”可以比较引用类型及基本类型;
- 当用 equals()方法进行比较时,对类 File、String、Date 及包装类来说,是比较类 型及内容而不考虑引用的是否是同一个实例;
- 用“==”进行比较时,符号两边的数据类型必须一致(可自动转换的数据类型除外),否则编译出错,而用 equals 方法比较的两个数据只要都是引用类型即可。
hashCode方法
hashCode 是按照一定的算法得到的一个数值,是对象的散列码值。 主要用来在集合中实现快速查找等操作,也可以用于对象的比较。在 Java 中,对 hashCode 的规定如下:
- 在同一个应用程序执行期间,对同一个对象调用 hashCode(),必须返回相同的整数结果——前提是 equals()所比较的信息都不曾被改动过。至于同一个应用程序在不同执 行期所得的调用结果,无需一致。
- 如果两个对象被 equals(Object)方法视为相等,那么对这两个对象调用hashCode()必须获得相同的整数结果。
- 如果两个对象被 equals(Object) 方法视为不相等,那么对这两个对象调用hashCode()不必产生不同的整数结果。然而程序员应该意识到,对不同对象产生不同的整数结果,有可能提升hashTable(后面会学到,集合框架中的一个类)的效率。
简单地说:如果两个对象相同,那么它们的 hashCode 值一定要相同;如果两个对象的hashCode 相同,它们并不一定相同。在 Java 规范里面规定,一般是覆盖 equals 方法应该连带覆盖hashCode 方法。
toString方法
toString()方法是 Object 类中定义的另一个重要方法,是对象的字符串表现形式,其格式为:public String toString(){……}
方法的返回值是 String 类型,用于描述当前对象的有关信息。Object 类中实现的toString() 方法是返回当前对象的类型和内存地址信息,但在一些子类(如 String,Date 等)中进行了 重写,也可以根据需要在用户自定义类型中重写 toString()方法,以返回更适用的信息。
除显式调用对象的 toString()方法外,在进行 String 与其它类型数据的连接操作时,会自动调用 toString()方法。
以上几种方法,在Java中是经常用到的,这里仅作简单介绍,让大家对Object类和其他类有所了解,后面还会进行详细说明。
*****************************************************************
Java语言包(java.lang)简介
Java语言包(java.lang)定义了Java中的大多数基本类,由Java语言自动调用,不需要显示声明。 该包中包含了Object类,Object类是整个类层次结构的根结点,同时还定义了基本数据类型的类,如:String、Boolean、Byter、Short等。这些类支持数字类型的转换和字符串的操作等,下面将进行简单介绍。Math类
Math类提供了常用的数学运算方法以及Math.PI和Math.E两个数学常量。 该类是final的,不能被继承,类中的方法和属性全部是静态,不允许在类的外部创建Math类的对象。因此,只能使用Math类的方法而不能对其作任何更改。 表8-1列出了Math类的主要方法。方法 | 功能 |
---|---|
int abs(int i) | 求整数的绝对值(另有针对long、float、double的方法) |
double ceil(double d) | 不小于d的最小整数(返回值为double型) |
double floor(double d) | 不大于d的最大整数(返回值为double型) |
int max(int i1,int i2) | 求两个整数中最大数(另有针对long、float、double的方法) |
int min(int i1,int i2) | 求两个整数中最小数(另有针对long、float、double的方法) |
double random() | 产生0~1之间的随机数 |
int round(float f) | 求最靠近f的整数 |
long round(double d) | 求最靠近d的长整数 |
double sqrt(double a) | 求平方根 |
double sin(double d) | 求d的sin值(另有求其他三角函数的方法如cos,tan,atan) |
double log(double x) | 求自然对数 |
double exp(double x) | 求e的x次幂(ex) |
double pow(double a, double b) | 求a的b次幂 |
【例8-2】产生10个10~100之间的随机整数。
//********** ep8_2.java **********
class ep8_2{
public static void main(String args[]){
int a;
System.out.print("随机数为:");
for(int i=1;i<=10;i++){
a=(int)((100-10+1)*Math.random()+10);
System.out.print(" "+a);
}
System.out.println();
}
}
运行结果: 随机数为:12 26 21 68 56 98 22 69 68 31
由于产生的是随机数,例8-2每次运行的结果都不会相同。若要产生[a,b]之间的随机数其通式为:
(b-a+1)*Math.random()+a
字符串类
字符串是字符的序列。在 Java 中,字符串无论是常量还是变量都是用类的对象来实现的。 java.lang 提供了两种字符串类:String 类和 StringBuffer 类。1.String 类
按照 Java 语言的规定,String 类是 immutable 的 Unicode 字符序列,其作用是实现一种不能改变的静态字符串。例如,把两个字符串连接起来的结果是生成一个新的字符串,而不会使原来的字符串改变。实际上,所有改变字符串的结果都是生成新的字符串,而不是改变原来字符串。
字符串与数组的实现很相似,也是通过 index 编号来指出字符在字符串中的位置的,编号从0 开始,第 2 个字符的编号为 1,以此类推。如果要访问的编号不在合法的范围内,系统会产生 StringIndexOutOfBoundsExecption 异常。如果 index 的值不是整数,则会产生编译错误。
String 类提供了如表 8-2 所示的几种字符串创建方法。
方法 | 功能 |
---|---|
String s=”Hello!” | 用字符串常量自动创建 String 实例。 |
String s=new String(String s) | 通过 String 对象或字符串常量传递给构造方法。 |
public String(char value[]) | 将整个字符数组赋给 String 构造方法。 |
public String(char value[], int offset, int count) | 将字符数组的一部分赋给 String 构造方法,offset 为起始下标,count为子数组长度。 |
2.StringBuffer 类
String 类不能改变字符串对象中的内容,只能通过建立一个新串来实现字符串的变化。如果字符串需要动态改变,就需要用 StringBuffer 类。StringBuffer 类主要用来实现字符串内容的添加、修改、删除,也就是说该类对象实体的内存空间可以自动改变大小,以便于存放一个可变的字符序列。
构造方法 | 说明 |
---|---|
StringBuffer() | 使用该无参数的构造方法创建的 StringBuffer 对象,初始容量为 16 个字符,当对象存放的字符序列大于 16 个字符时,对象的容量自动增加。该对象可以通过 length()方法获取实体中存放的字符序列的长度,通过 capacity()方法获取当前对象的实际容量。 |
StringBuffer(int length) | 使用该构造方法创建的 StringBuffer 对象,其初始容量为参数 length 指定的字符个数,当对象存放的字符序列的长度大于 length 时,对象的容量自动增加,以便存放所增加的字符。 |
StringBuffer(Strin str) | 使用该构造方法创建的 StringBuffer 对象,其初始容量为参数字符串 str 的长度再加上 16 个字符。 |
方法 | 说明 |
---|---|
append() | 使用 append() 方法可以将其他 Java 类型数据转化为字符串后再追加到 StringBuffer 的对象中。 |
insert(int index, String str) | insert() 方法将一个字符串插入对象的字符序列中的某个位置。 |
setCharAt(int n, char ch) | 将当前 StringBuffer 对象中的字符序列 n 处的字符用参数 ch 指定的字符替换,n 的值必须是非负的,并且小于当前对象中字符串序列的长度。 |
reverse() | 使用 reverse()方法可以将对象中的字符序列翻转。 |
delete(int n, int m) | 从当前 StringBuffer 对象中的字符序列删除一个子字符序列。这里的 n 指定了需要删除的第一个字符的下标,m 指定了需要删除的最后一个字符的下一个字符的下标,因此删除的子字符串从 n~m-1。 |
replace(int n, int m, String str) | 用 str 替换对象中的字符序列,被替换的子字符序列由下标 n 和 m 指定。 |
**********************************************************************
Java日期和时间类简介
Java 的日期和时间类包含在 Java 实用程序包(java.util)中。利用日期时间类提供的方法,可以获取当前的日期和时间,创建日期和时间参数,计算和比较时间。Date 类
Date 类是 Java 中的日期时间类,其构造方法为:Date()
使用当前的日期和时间初始化一个对象。
Date(long millisec)
该构造方法带有一个参数,使用这个参数从 1970 年 01 月 01 日 00 时(格林威治时间)开始以毫秒计算时间。例如:
Date dt1=new Date(1000);
如果运行 Java 程序的本地时区是北京时区(与格林威治时间相差 8 小时),那么对象 dt1 就是 1970 年 01 月 01 日 08 时 00 分 01 秒。
【例 8-6】显示时间的例子。
//********** ep8_6.java **********
import java.util.Date;
class ep8_6{
public static void main(String args[]){
Date da=new Date(); //创建时间对象
System.out.println(da); //显示时间和日期
long msec=da.getTime();
System.out.println("从 1970 年 1 月 1 日 0 时到现在共有:"+msec+"毫秒");
}
}
运行结果:
Mon Feb 05 22:50:05 CST 2007
从 1970 年 1 月 1 日 0 时到现在共有:1170687005390 毫秒
一些比较常用的 Date 类方法如表 8-3 所示。
方法 | 功能 |
---|---|
boolean after(Date date) | 若调用 Date 对象所包含的日期比 date 指定的对象所包含的日期晚,返回 true,否则返回 false。 |
boolean before(Date date) | 返回字符串位置 index 处的字符。 |
public Boolean equals(Object o) | 若调用 Date 对象所包含的日期比 date 指定的对象所包含的日期早,返回 true,否则返回 false。 |
Object clone() | 复制调用 Date 对象。 |
int compareTo(Date date) | 比较调用对象所包含的日期和指定的对象包含的日期,若相等返回 0;若前者比后者早,返回负值;否则返回正值。 |
long getTime() | 以毫秒数返回从 1970 年 01 月 01 日 00 时到目前的时间。 |
int hashCode() | 返回调用对象的散列值。 |
void setTime(long time) | 根据 time 的值,设置时间和日期。time 值从 1970 年 01 月 01 日 00 时开始计算。 |
String toString() | 把调用的 Date 对象转换成字符串并返回结果。 |
public Static String valueOf(type variable) | 把 variable 转换为字符串。 |
【例 8-7】用不同的格式输出时间。
//********** ep8_7.java **********
import java.util.Date;
import java.text.SimpleDateFormat;
class ep8_7{
public static void main(String args[]){
Date da=new Date();
System.out.println(da);
SimpleDateFormat ma1=new SimpleDateFormat("yyyy 年 MM 月 dd 日 E 北京时间");
System.out.println(ma1.format(da));
SimpleDateFormat ma2=new SimpleDateFormat("北京时间:yyyy 年 MM 月 dd 日 HH 时 mm 分 ss 秒");
System.out.println(ma2.format(-1000));
}
}
运行结果:
Mon Feb 05 23:20:00 CST 2007
2007 年 02 月 05 日星期一 北京时间
北京时间:1970 年 01 月 01 日 07 时 59 分 59 秒
Calendar 类
抽象类 Calendar 提供了一组方法,允许把以毫秒为单位的时间转换成一些有用的时间组成部分。Calendar 不能直接创建对象,但可以使用静态方法 getInstance()获得代表当前日期的日历对象,如:Calendar calendar=Calendar.getInstance();
该对象可以调用下面的方法将日历翻到指定的一个时间:
void set(int year,int month,int date);
void set(int year,int month,int date,int hour,int minute);
void set(int year,int month,int date,int hour,int minute,int second);
若要调用有关年份、月份、小时、星期等信息,可以通过调用下面的方法实现:
int get(int field);
其中,参数 field 的值由 Calendar 类的静态常量决定。其中:YEAR 代表年,MONTH 代表月,HOUR 代表小时,MINUTE 代表分,如:
calendar.get(Calendar.MONTH);
如果返回值为 0 代表当前日历是一月份,如果返回 1 代表二月份,依此类推。由 Calendar 定义的一些常用方法如表 8-4 所示。
方法 | 功能 |
---|---|
abstract void add(int which,int val) | 将 val 加到 which 所指定的时间或者日期中,如果需要实现减的功能,可以加一个负数。which 必须是 Calendar 类定义的字段之一,如 Calendar.HOUR |
boolean after(Object calendarObj) | 如果调用 Calendar 对象所包含的日期比 calendarObj 指定的对象所包含的日期晚,返回 true,否则返回 false |
boolean before(Object calendarObj) | 如果调用 Calendar 对象所包含的日期比 calendarObj 指定的对象所包含的日期早,返回 true,否则返回 false |
final void clear() | 对调用对象包含的所有时间组成部分清零 |
final void clear(int which) | 对调用对象包含的 which 所指定的时间组成部分清零 |
boolean equals(Object calendarObj) | 如果调用 Calendar 对象所包含的日期和 calendarObj 指定的对象所包含的日期相等,返回 true,否则返回 false |
int get(int calendarField) | 返回调用 Calendar 对象的一个时间组成部分的值,这个组成部分由 calendarField指定,可以被返回的组成部分如:Calendar.YEAR,Calendar.MONTH 等 |
static Calendar getInstance() | 返回使用默认地域和时区的一个 Calendar 对象 |
final Date getTime() | 返回一个和调用对象时间相等的 Date 对象 |
final boolean isSet(int which) | 如果调用对象所包含的 which 指定的时间部分被设置了,返回 true,否则返回 false |
final void set(int year,int month) | 设置调用对象的各种日期和时间部分 |
final void setTime(Date d) | 从 Date 对象 d 中获得日期和时间部分 |
void setTimeZone(TimeZone t) | 设置调用对象的时区为 t 指定的那个时区 |
GregorianCalendar 类
GregorianCalendar 是一个具体实现 Calendar 类的类,该类实现了公历日历。Calendar 类的getInstance()方法返回一个 GregorianCalendar,它被初始化为默认的地域和时区下的当前日期和时间。GregorianCalendar 类定义了两个字段:AD 和 BC,分别代表公元前和公元后。其默认的构造方法 GregorianCalendar()以默认的地域和时区的当前日期和时间初始化对象,另外也可以指定地域和时区来建立一个 GregorianCalendar 对象,例如:
GregorianCalendar(Locale locale);
GregorianCalendar(TimeZone timeZone);
GregorianCalendar(TimeZone timeZone,Locale locale);
GregorianCalendar 类提供了 Calendar 类中所有的抽象方法的实现,同时还提供了一些附加的方法,其中用来判断闰年的方法为:
Boolean isLeapYear(int year);
如果 year 是闰年,该方法返回 true,否则返回 false。
********************************************************************
Java向量及其应用
向量(Vector)是 java.util 包提供的一个工具类,该类实现了可扩展的对象数组。向量和数组的区别
向量和数组相似,都可以保存列表对象。但是数组只能保存固定大小的列表,而向量却提供了一种类似于“动态数组”的功能, 向量与数组的重要区别之一就是向量的容量是可变的 。向量和数组分别适用于不同的场合,一般来说,下列场合更适合于使用向量:
- 如果需要频繁进行对象的插入和删除工作,或者因为需要处理的对象数目不定。
- 列表成员全部都是对象,或者可以方便的用对象表示。
- 需要很快确定列表内是否存在某一特定对象,并且希望很快了解到对象的存放位置。
向量作为一种对象提供了比数组更多的方法,但需要注意的是,向量只能存储对象,不能直接存储简单数据类型,因此下列场合适用于使用数组:
- 所需处理的对象数目大致可以确定。
- 所需处理的是简单数据类型。
向量的使用
向量必须要先创建后使用,向量的大小是向量中元素的个数,向量的容量是被分配用来存储元素的内存大小,其大小总是大于向量的大小。 下面是 Vector 的构造方法:Vector(); //创建空向量,初始大小为 10
Vector(int capacity); //创建初始容量为 capacity 指定的空向量
Vector(int capacity,int incr) //指定向量容量及其增量参数创建空向量
为优化存储管理,Java 的每个向量均可以使用一个“初始容量”和一个“容量增量”,在初始容量满了以后,下一次在存储一个对象到向量中时,这个向量自动为该对象和额外的对象分配空间。通过分配多于所需的内存空间,向量减少了必须的内存分配的数目。这样能够有效地减少分配所消耗的时间,每次分配的额外空间数目将由创建向量时指定的增量所决定。
如果没有指定增量或增量为 0,则该向量的大小在每次分配时都将加倍。除了构造方法外,向量类还提供了三个属性变量,分别为:
protected int capacityIncrement; //当向量大小不足时,所用的增量大小
protected int elementCount; //向量的元素个数
protected Object elementData[]; //向量成员数据所用的缓冲
一旦创建了向量类的实例,就可以用其方法来执行插入、删除以及查找对象等操作,向量类提供了极为丰富的方法,表 8-5 中给出了其中一些主要的方法。
方法 | 功能 |
---|---|
void addElement(Object element) | 将给定对象 element 增加到向量末尾 |
int capacity() | 返回向量容量 |
boolean contains(Object element) | 若向量中包含了 element 返回 true,否则返回 false |
void copyInto(Object Array[]) | 将向量元素复制到指定数组 |
synchronized Object elementAt(int index) | 返回指定下标的元素,若下标非法,抛出 ArrayIndexOutOfBoundsExecption 异常 |
void ensureCapacity(int size) | 将向量的最小容量设为 size |
synchronized Object firstElement() | 返回向量的第一个元素,若向量为空,抛出 NoSuchElementException 异常 |
int indexOf(Object element) | 返回 element 的下标,若对象不存在返回-1 |
int indexOf (Object element,int start) | 从指定位置(start)开始搜索向量,返回对象所对应的下标值,若未找到返回-1 |
void insertElementAt (Object obj,int index) | 将给定的对象插入到指定的下标处 |
boolean isEmpty() | 若向量不包括任何元素,返回 true,否则返回 false |
synchronized Object lastElement() | 返回向量的最后一个元素,若向量为空,抛出 NoSuchElementException 异常 |
int lastIndexOf(Object element) | 从向量末尾向前搜索向量,返回对象的下标值 |
int lastIndexOf(Object element,int start) | 从指定位置开始向前搜索向量,返回给定对象的下标值,若未找到返回-1 |
void removeAllElements() | 删除向量中的所有对象,向量变成空向量 |
boolean removeElement(Object element) | 从向量中删除指定对象 element,若给定的对象在向量中保存多次,则只删除其第一个实例,如果删除成功,返回 true,如果没发现对象,则返回 false |
void removeElementAt(int index) | 删除由 index 指定位置处的元素 |
void setElementAt(Object obj,int index) | 将给定对象存放到给定下标处,该下标处的原有对象丢失 |
void setSize(int size) | 将向量中的元素个数设为 size,如果新的长度小于原来的长度,元素将丢失,若新的长度大于原来的长度,则在其后增加 null 元素 |
int size() | 返回向量中当前元素的个数 |
String toString() | 将向量转换成字符串 |
void trimToSize() | 将向量的容量设为与当前拥有的元素个数相等 |
Vector vector=new Vector();
【例 8-11】测试向量大小和容量的变化及元素的遍历。
//********** ep8_11.java **********
import java.util.*;
class ep8_11{
public static void main(String args[]){
Vector <Integer> v=new Vector<Integer>(3,2);
System.out.println("向量中的元素个数为:"+v.size());
System.out.println("向量的容量为:"+v.capacity());
v.addElement(1);
v.addElement(2);
v.addElement(3);
v.addElement(4);
System.out.println("加入四个元素后容量为:"+v.capacity());
v.addElement(5);
System.out.println("当前向量的容量为:"+v.capacity());
v.addElement(6);
v.addElement(7);
v.addElement(8);
System.out.println("当前向量的容量为:"+v.capacity());
System.out.println("第一个元素为:"+v.firstElement());
System.out.println("最后一个元素为:"+v.lastElement());
if(v.contains(3)){
System.out.println("向量中包含 3");
}
System.out.println("\n 向量中的元素为:");
for(int i=0;i<v.size();i++){
System.out.print(v.get(i)+" ");
}
}
}
运行结果:
向量中的元素个数为:0
向量的容量为:3
加入四个元素后容量为:5
当前向量的容量为:5
当前向量的容量为:9
第一个元素为:1
最后一个元素为:8
向量中包含 3
向量中的元素为:
1 2 3 4 5 6 7 8
向量的遍历除了可以使用 get 方法循环访问向量的所有元素外,还可以使用 iterator(),返回一个可以遍历的元素列表,然后通过 hasNext()和 next()方法实现遍历,例如:
Iterator a=v.iterator();
while(v.hasNext()){
System.out.println(a.next());
}
//********** ep8_11.java **********
import java.util.*;
class ep8_11{
public static void main(String args[]){
Vector <Integer> v=new Vector<Integer>(3,2);
System.out.println("向量中的元素个数为:"+v.size());
System.out.println("向量的容量为:"+v.capacity());
v.addElement(1);
v.addElement(2);
v.addElement(3);
v.addElement(4);
System.out.println("加入四个元素后容量为:"+v.capacity());
v.addElement(5);
System.out.println("当前向量的容量为:"+v.capacity());
v.addElement(6);
v.addElement(7);
v.addElement(8);
System.out.println("当前向量的容量为:"+v.capacity());
System.out.println("第一个元素为:"+v.firstElement());
System.out.println("最后一个元素为:"+v.lastElement());
if(v.contains(3)){
System.out.println("向量中包含 3");
}
System.out.println("\n 向量中的元素为:");
for(int i=0;i<v.size();i++){
System.out.print(v.get(i)+" ");
}
}
}
运行结果:
向量中的元素个数为:0
向量的容量为:3
加入四个元素后容量为:5
当前向量的容量为:5
当前向量的容量为:9
第一个元素为:1
最后一个元素为:8
向量中包含 3
向量中的元素为:
1 2 3 4 5 6 7 8
向量的遍历除了可以使用 get 方法循环访问向量的所有元素外,还可以使用 iterator(),返回一个可以遍历的元素列表,然后通过 hasNext()和 next()方法实现遍历,例如:
Iterator a=v.iterator();
while(v.hasNext()){
System.out.println(a.next());
}
***************************************************************
Java哈希表及其应用
哈希表也称为散列表,是用来存储群体对象的集合类结构。什么是哈希表
数组和向量都可以存储对象,但对象的存储位置是随机的,也就是说对象本身与其存储位置之间没有必然的联系。当要查找一个对象时,只能以某种顺序(如顺序查找或二分查找)与各个元素进行比较,当数组或向量中的元素数量很多时,查找的效率会明显的降低。一种有效的存储方式,是不与其他元素进行比较,一次存取便能得到所需要的记录。这就需要在对象的存储位置和对象的关键属性(设为 k)之间建立一个特定的对应关系(设为 f),使每个对象与一个唯一的存储位置相对应。在查找时,只要根据待查对象的关键属性 k 计算f(k)的值即可。如果此对象在集合中,则必定在存储位置 f(k)上,因此不需要与集合中的其他元素进行比较。称这种对应关系 f 为哈希(hash)方法,按照这种思想建立的表为哈希表。
Java 使用哈希表类(Hashtable)来实现哈希表,以下是与哈希表相关的一些概念:
- 容量(Capacity):Hashtable 的容量不是固定的,随对象的加入其容量也可以自动增长。
- 关键字(Key):每个存储的对象都需要有一个关键字,key 可以是对象本身,也可以是对象的一部分(如某个属性)。要求在一个 Hashtable 中的所有关键字都是唯一的。
- 哈希码(Hash Code):若要将对象存储到 Hashtable 上,就需要将其关键字 key 映射到一个整型数据,成为 key 的哈希码。
- 项(Item):Hashtable 中的每一项都有两个域,分别是关键字域 key 和值域 value(存储的对象)。Key 和 value 都可以是任意的 Object 类型的对象,但不能为空。
- 装填因子(Load Factor):装填因子表示为哈希表的装满程度,其值等于元素数比上哈希表的长度。
哈希表的使用
哈希表类主要有三种形式的构造方法:Hashtable(); //默认构造函数,初始容量为 101,最大填充因子 0.75
Hashtable(int capacity);
Hashtable(int capacity,float loadFactor)
哈希表类的主要方法如表 8-6 所示。
方法 | 功能 |
---|---|
void clear() | 重新设置并清空哈希表 |
boolean contains(Object value) | 确定哈希表内是否包含了给定的对象,若有返回 true,否则返回 false |
boolean containsKey(Object key) | 确定哈希表内是否包含了给定的关键字,若有返回 true,否则返回 false |
boolean isEmpty() | 确认哈希表是否为空,若是返回 true,否则返回 false |
Object get(Object key) | 获取对应关键字的对象,若不存在返回 null |
void rehash() | 再哈希,扩充哈希表使之可以保存更多的元素,当哈希表达到饱和时,系统自动调用此方法 |
Object put(Object key,Object value) | 用给定的关键字把对象保存到哈希表中,此处的关键字和元素均不可为空 |
Object remove(Object key) | 从哈希表中删除与给定关键字相对应的对象,若该对象不存在返回 null |
int size() | 返回哈希表的大小 |
String toString() | 将哈希表内容转换为字符串 |
哈希表的创建也可以通过 new 操作符实现。其语句为:
HashTable has=new HashTable();
【例 8-12】哈希表的遍历。
//********** ep8_12.java **********
import java.util.*;
class ep8_12{
public static void main(String args[]){
Hashtable has=new Hashtable();
has.put("one",new Integer(1));
has.put("two",new Integer(2));
has.put("three",new Integer(3));
has.put("four",new Double(12.3));
Set s=has.keySet();
for(Iterator<String> i=s.iterator();i.hasNext();){
System.out.println(has.get(i.next()));
}
}
}
运行结果:
2
1
3
12.3
*********************************************************************