本章介绍Java的实用工具类库java.util包。在这个包中,Java提供了一些实用的方法和数据结构。例如,Java提供日期(Data)类、日历(Calendar)类来产生和获取日期及时间,提供随机数(Random)类产生各种类型的随机数,还提供了堆栈(Stack)、向量(Vector) 、位集合(Bitset)以及哈希表(Hashtable)等类来表示相应的数据结构。
图1.1给出了java.util包的基本层次结构图。下面我们将具体介绍其中几个重要的类。
┌java.util.BitSet
│java.util.Calendar
│ └java.util.GregorianCalendar
│java.util.Date
│java.util.Dictionary
│ └java.util.Hashtable
│ └java.util.Properties
│java.util.EventObject
│java.util.ResourceBundle
┌普通类┤ ├java.util.ListResourceBundle
│ │ └java.util.PropertyResourceBundle
│ │java.util.Local
│ │java.util.Observable
│ │java.util.Random
│ │java.util.StringTokenizer
│ │java.util.Vector
│ │ └java.util.Stack
Java.util┤ └java.util.TimeZone
│ └java.util.SimpleTimeZone
│ ┌java.util.Enumeration
├接 口┤java.util.EventListener
│ └java.util.Observer
│ ┌java.util.EmptyStackException
└异常类┤java.util.MissingResourceException
│java.util.NoSuchElementException
└java.util.TooManyListenersException
图1.1 java.util包的基本层次结构
1.2 日期类Date
Java在日期类中封装了有关日期和时间的信息,用户可以通过调用相应的方法来获取系统时间或设置日期和时间。Date类中有很多方法在JDK1.0公布后已经过时了,在8.3中我们将介绍JDK1.0中新加的用于替代Date的功能的其它类。
在日期类中共定义了六种构造函数。
(1)public Date()
创建的日期类对象的日期时间被设置成创建时刻相对应的日期时间。
例
Date today=new Date();//today被设置成创建时刻相对应的日期时间。
(2)public Date (long date)long 型的参数date可以通过调用Date类中的static方法parse(String s)来获得。
例
ong l=Date.parse("Mon 6 Jan 1997 13:3:00");
Date day=new Date(l);
//day中时间为1997年 1月6号星期一,13:3:00。
按字符串s产生一日期对象。s的格式与方法parse中字符串参数的模式相同。
例
Date day=new Date("Mon 6 Jan 1997 13:3:00");
//day 中时间为1997年1月6号星期一,13:3:00.
(5)public Date(int year,int month,int date,int hrs,int min)
(6)public Date(int year,int month,int date,int hrs,int min,int sec)
按给定的参数创建一日期对象。
参数说明:
year的值为:需设定的年份-1900。例如需设定的年份是1997则year的值应为97,即1997-1900的结果。所以Date中可设定的年份最小为1900;
month的值域为0~11,0代表1月,11表代表12月;
date的值域在1~31之间;
hrs的值域在0~23之间。从午夜到次日凌晨1点间hrs=0,从中午到下午1点间hrs=12;
min和sec的值域在0~59之间。
例
Date day=new Date(11,3,4);
//day中的时间为:04-Apr-11 12:00:00 AM
例 设定时间为1910年2月30日,它将被解释成3月2日。
Date day=new Date(10,1,30,10,12,34);
System.out.println("Day's date is:"+day);
//打印结果为:Day's date is:Web Mar 02 10:13:34 GMT+08:00 1910
(1)public static long UTC(int year,int month,int date,int hrs. int min,int sec)
该方法将利用给定参数计算UTC值。UTC是一种计时体制,与GMT(格林威治时间)的计时体系略有差别。UTC计时体系是基于原子时钟的,而GTMT计时体系是基于天文学观测的。计算中使用的一般为GMT计时体系。(2)public static long parse(String s)
该方法将字符串s转换成一个long型的日期。在介绍构造方法Date(long date)时曾使用过这个方法。字符串s有一定的格式,一般为:
(星期 日 年 时间GMT+时区)
若不注明时区,则为本地时区。
(3)public void setMonth(int month)
(4)public int getMonth()
获取的月份的值域为0~11,0代表1月,11代表12月。
(5)public String toString()
(6)public String toLocalString()
(7)public String toGMTString()
(8)public int getTimezoneOffset()
该方法用于获取日期对象的时区偏移量。例8.1中对上面介绍的Date类中的基本方法进行了具体的应用,并打印了相应的结果。由于使用了一些过时的方法,所以编译时会有警告信息。另外,由于本例中的时间表示与平台有关,不同的JDK版本对此处理不完全相同,因此不同版本的JDK执行本例的结果可能有细微差异。
例1.1
DateApp.java
import java.lang.System;
import java.util.Date;
public class DateApp{
public static void main(String args[]){
Date today=new Date();
//today中的日期被设成创建时刻的日期和时间,假设创建时刻为1997年3月
//23日17时51分54秒。
System.out.println("Today's date is "+today);
//返回一般的时间表示法,本例中结果为
//Today's date is Fri May 23 17:51:54 1997
System.out.println("Today's date(Internet GMT)is:"
+today.toGMTString());
//返回结果为GMT时间表示法,本例中结果为
//Today's date(Internet GMT)is: 23 May 1997 09:51:54:GMT
System.out.println("Today's date(Locale) is:"
+today.toLocaleString());
//返回结果为本地习惯的时间表示法,结果为
//Today's date(Locale)is:05/23/97 17:51:54
System.out.println("Today's year is: "+today.getYear());
System.out.println("Today's month is: "+(today.getMonth()+1));
System.out.println("Today's date is: "+today.getDate());
//调用Date类中方法,获取年月日的值。
//下面调用了不同的构造方法来创建Date类的对象。
Date day1=new Date(100,1,23,10,12,34);
System.out.println("Day1's date is: "+day1);
Date day2=new Date("Sat 12 Aug 1996 13:3:00");
System.out.println("Day2's date is: "+day2);
long l= Date.parse("Sat 5 Aug 1996 13:3:00 GMT+0800");
Date day3= new Date(l);
System.out.println("Day3's date(GMT)is: "+day3.toGMTString());
System.out.println("Day3's date(Locale)is: "
+day3.toLocaleString());
System.out.println("Day3's time zone offset is:"
+day3.getTimezoneOffset());
}
}
E:\java\tutorial\java01>java DateApp
Today's date is Thu Dec 27 17:58:16 CST 2001
Today's date(Internet GMT)is:27 Dec 2001 09:58:16 GMT
Today's date(Locale) is:2001-12-27 17:58:16
Today's year is: 101
Today's month is: 12
Today's date is: 27
Day1's date is: Wed Feb 23 10:12:34 CST 2000
Day2's date is: Fri Aug 12 13:03:00 CST 1996
Day3's date(GMT)is: 5 Aug 1996 05:03:00 GMT
Day3's date(Locale)is: 1996-8-5 13:03:00
Day3's time zone offset is:-480
E:\java\tutorial\java01>
在早期的JDK版本中,日期(Date)类附有两大功能:(1)允许用年、月、日、时、分、秒来解释日期:(2)允许对表示日期的字符串进行格式化和句法分析。在JDK1.1中提供了类Calendar来完成第一种功能,类DateFormat来完成第二项功能。dateFormat是java.text包中的一个类。与Date类有所不同的是,DateFormat类接受用各种语言和不同习惯表示的日期字符串。本节将介绍java.util包中的类Calendar及其它新增加的相关的类。
类Calendar是一个抽象类,它完成日期(Date)类和普通日期表示法(即用一组整型域如YEAR,MONTH,DAY,HOUR表示日期)之间的转换。
由于所使用的规则不同,不同的日历系统对同一个日期的解释有所不同。在JDK1.1中提供了Calendar类一个子类GregorianCalendar??它实现了世界上普遍使用的公历系统。当然用户也可以通过继承Calendar类,并增加所需规则,以实现不同的日历系统。
第GregorianCalendar继承了Calendar类。本节将在介绍类GregorianCalendar的同时顺带介绍Calendar类中的相关方法。
类GregorianCalendar提供了七种构造函数:
(1)public GregorianCalendar()
创建的对象中的相关值被设置成指定时区,缺省地点的当前时间,即程序运行时所处的时区、地点的当前时间。(2)public GregorianCalendar(TimeZone zone)
创建的对象中的相关值被设置成指定时区zone,缺省地点的当前时间。(3)public GregorianCalendar(Locale aLocale)
创建的对象中的相关值被设置成缺省时区,指定地点aLocale的当前时间。(4)public GregorianCalendar(TimeZone zone,Local aLocale)
创建的对象中的相关值被设置成指定时区,指定地点的当前时间。上面使用到的类TimeZone的性质如下:
TimeZone是java.util包中的一个类,其中封装了有关时区的信息。每一个时区对应一组ID。类TimeZone提供了一些方法完成时区与对应ID两者之间的转换。
(Ⅰ)已知某个特定的ID,可以调用方法
public static synchronized TimeZone getTimeZone(String ID)
来获取对应的时区对象。例 太平洋时区的ID为PST,用下面的方法可获取对应于太平洋时区的时区对象:
TimeZone tz=TimeZone.getTimeZone("PST");
调用方法getDefault()可以获取主机所处时区的对象。TimeZone tz=TimeZone.getDefault();
(Ⅱ)调用以下方法可以获取时区的ID>■public static synchronized String[] getavailableIDs(int rawOffset)
根据给定时区偏移值获取ID数组。同一时区的不同地区的ID可能不同,这是由于不同地区对是否实施夏时制意见不统一而造成的。例String s[]=TimeZone.getAvailableIDs(-7*60*60*1000);
打印s,结果为s[0]=PNT,s[1]=MST
■public static synchronized String[] getAvailableIDs()
获取提供的所有支持的ID。■public String getID()
获取特定时区对象的ID。例
TimeZone tz=TimeZone.getDefault();
String s=tz.getID();
上面使用类的对象代表了一个特定的地理、政治或文化区域。Locale只是一种机制,它用来标识一类对象,Local本身并不包含此类对象。
要获取一个Locale的对象有两种方法:
(Ⅰ)调用Locale类的构造方法
Locale(String language,String country)
Locale(String language,String country,String variant)
country??在ISO-3166中定义的代码,由两个大写字母组成。
variant??售货商以及特定浏览器的代码,例如使用WIN代表Windows。
(Ⅱ)调用Locale类中定义的常量
Local类提供了大量的常量供用户创建Locale对象。
例 Locale.CHINA
为中国创建一个Locale的对象。
类TimeZone和类Locale中的其它方法,读者可查阅API。
(5)public GregorianCalendar(int year,int month,int date)
(6)public GregorianCalendar(int year,int month,int date,int hour,int minute)
(7)public GregorianCalendar(int year,int month,int date,int hour,int minute,int second)
参数说明:
year-设定日历对象的变量YEAR;month-设定日历对象的变量MONTH;
date-设定日历对象的变量DATE;hour-设定日历对象的变量HOUR_OF_DAY;
minute-设定日历对象的变量MINUTE;second-设定日历对象的变量SECOND。
与Date类中不同的是year的值没有1900这个下限,而且year的值代表实际的年份。month的含义与Date类相同,0代表1月,11代表12月。
例
GregorianCalendar cal=new GregorianCalendar(1991,2,4)
cal的日期为1991年3月4号。除了与Date中类似的方法外,Calendar类还提供了有关方法对日历进行滚动计算和数学计算。计算规则由给定的日历系统决定。进行日期计算时,有时会遇到信息不足或信息不实等特殊情况。Calendar采取了相应的方法解决这些问题。当信息不足时将采用缺省设置,在GregorianCalendar类中缺省设置一般为YEAR=1970,MONTH=JANUARY,DATE=1。
当信息不实时,Calendar将按下面的次序优先选择相应的Calendar的变量组合,并将其它有冲突的信息丢弃。
MONTH+DAY_OF_MONTH
MONTH+WEEK_OF_MONTH+DAY_OF_WEEK
MONTH+DAY_OF_WEEK_OF_MONTH+DAY_OF_WEEK
DAY_OF+YEAR
DAY_OF_WEEK_WEEK_OF_YEAR
HOUR_OF_DAY
Java实用工具类库中的类java.util.Random提供了产生各种类型随机数的方法。它可以产生int、long、float、double以及Goussian等类型的随机数。这也是它与java.lang.Math中的方法Random()最大的不同之处,后者只产生double型的随机数。
类Random中的方法十分简单,它只有两个构造方法和六个普通方法。
构造方法:
(1)public Random()
(2)public Random(long seed)
普通方法:
(1)public synonronized void setSeed(long seed)
该方法是设定基值seed。(2)public int nextInt()
该方法是产生一个整型随机数。(3)public long nextLong()
该方法是产生一个long型随机数。(4)public float nextFloat()
该方法是产生一个Float型随机数。(5)public double nextDouble()
该方法是产生一个Double型随机数。(6)public synchronized double nextGoussian()
该方法是产生一个double型的Goussian随机数。例1.2
RandomApp.java。
//import java.lang.*;
import java.util.Random;
public class RandomApp{
public static void main(String args[]){
Random ran1=new Random();
Random ran2=new Random(12345);
//创建了两个类Random的对象。
System.out.println("The 1st set of random numbers:");
System.out.println("\t Integer:"+ran1.nextInt());
System.out.println("\t Long:"+ran1.nextLong());
System.out.println("\t Float:"+ran1.nextFloat());
System.out.println("\t Double:"+ran1.nextDouble());
System.out.println("\t Gaussian:"+ran1.nextGaussian());
//产生各种类型的随机数
System.out.print("The 2nd set of random numbers:");
for(int i=0;i<5;i++){
System.out.println(ran2.nextInt()+" ");
if(i==2) System.out.println();
//产生同种类型的不同的随机数。
System.out.println();//原文如此
}
}
}
E:\java01>java RandomApp
The 1st set of random numbers:
Integer:-173899656
Long:8056223819738127077
Float:0.6293638
Double:0.7888394520265607
Gaussian:0.5015701094568733
The 2nd set of random numbers:1553932502
-2090749135
-287790814
-355989640
-716867186
E:\java01>
Java.util.Vector提供了向量(Vector)类以实现类似动态数组的功能。在Java语言中。正如在一开始就提到过,是没有指针概念的,但如果能正确灵活地使用指针又确实可以大大提高程序的质量,比如在C、C++中所谓“动态数组”一般都由指针来实现。为了弥补这点缺陷,Java提供了丰富的类库来方便编程者使用,Vector类便是其中之一。事实上,灵活使用数组也可完成向量类的功能,但向量类中提供的大量方法大大方便了用户的使用。
创建了一个向量类的对象后,可以往其中随意地插入不同的类的对象,既不需顾及类型也不需预先选定向量的容量,并可方便地进行查找。对于预先不知或不愿预先定义数组大小,并需频繁进行查找、插入和删除工作的情况,可以考虑使用向量类。
向量类提供了三种构造方法:
public vector()
public vector(int initialcapacity,int capacityIncrement)
public vector(int initialcapacity)
在Vector类中提供了各种方法方便用户使用:
■插入功能
(1)public final synchronized void addElement(Object obj)
将obj插入向量的尾部。obj可以是任何类的对象。对同一个向量对象,可在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数值转换成相应的对象。例 要插入一个整数1时,不要直接调用v1.addElement(1),正确的方法为:
Vector v1=new Vector();
Integer integer1=new Integer(1);
v1.addElement(integer1);
(2)public final synchronized void setElementAt(object obj,int index)
将index处的对象设成obj,原来的对象将被覆盖。(3)public final synchronized void insertElementAt(Object obj,int index)
在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。■删除功能
(1)public final synchronized void removeElement(Object obj)
从向量中删除obj。若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。(2)public final synchronized void removeAllElement()
删除向量中所有的对象。(3)public final synchronized void removeElementlAt(int index)
删除index所指的地方的对象。■查询搜索功能
(1)public final int indexOf(Object obj)
从向量头开始搜索obj ,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1。(2)public final synchronized int indexOf(Object obj,int index)
从index所表示的下标处开始搜索obj。(3)public final int lastIndexOf(Object obj)
从向量尾部开始逆向搜索obj。(4)public final synchronized int lastIndexOf(Object obj,int index)
从index所表示的下标处由尾至头逆向搜索obj。(5)public final synchronized Object firstElement()
获取向量对象中的首个obj。(6)public final synchronized Object lastelement()
获取向量对象中的最后一个obj。了解了向量的最基本的方法后,我们来看一下例8.3VectorApp.java。
例1.3
VectorApp.java。
import java.util.Vector;
import java.lang.*;//这一句不应该要,但原文如此
import java.util.Enumeration;
public class VectorApp{
public static void main(String[] args){
Vector v1=new Vector();
Integer integer1=new Integer(1);
v1.addElement("one");
//加入的为字符串对象
v1.addElement(integer1);
v1.addElement(integer1);
//加入的为Integer的对象
v1.addElement("two");
v1.addElement(new Integer(2));
v1.addElement(integer1);
v1.addElement(integer1);
System.out.println("The vector v1 is:\n\t"+v1);
//将v1转换成字符串并打印
v1.insertElementAt("three",2);
v1.insertElementAt(new Float(3.9),3);
System.out.println("The vector v1(used method insertElementAt()) is:\n\t "+v1);
//往指定位置插入新的对象,指定位置后的对象依次往后顺延
v1.setElementAt("four",2);
System.out.println("The vector v1(used method setElementAt()) is:\n\t "+v1);
//将指定位置的对象设置为新的对象
v1.removeElement(integer1);
//从向量对象v1中删除对象integer1由于存在多个integer1所以从头开始
//找,删除找到的第一个integer1
Enumeration enum=v1.elements();
System.out.print("The vector v1(used method removeElement())is:");
while(enum.hasMoreElements())
System.out.print(enum.nextElement()+" ");
System.out.println();
//使用枚举类(Enumeration)的方法来获取向量对象的每个元素
System.out.println("The position of object 1(top-to-bottom):"
+ v1.indexOf(integer1));
System.out.println("The position of object 1(tottom-to-top):"
+v1.lastIndexOf(integer1));
//按不同的方向查找对象integer1所处的位置
v1.setSize(4);
System.out.println("The new vector(resized the vector)is:"+v1);
//重新设置v1的大小,多余的元素被行弃
}
}
E:\java01>java VectorApp
The vector v1 is:
[one, 1, 1, two, 2, 1, 1]
The vector v1(used method insertElementAt()) is:
[one, 1, three, 3.9, 1, two, 2, 1, 1]
The vector v1(used method setElementAt()) is:
[one, 1, four, 3.9, 1, two, 2, 1, 1]
The vector v1(used method removeElement())is:one four 3.9 1 two 2 1 1
The position of object 1(top-to-bottom):3
The position of object 1(tottom-to-top):7
The new vector(resized the vector)is:[one, four, 3.9, 1]
E:\java01>
(1)类Vector定义了方法
public final int size()
此方法用于获取向量元素的个数。它的返回值是向是中实际存在的元素个数,而非向量容量。可以调用方法capactly()来获取容量值。方法:
public final synchronized void setsize(int newsize)
此方法用来定义向量大小。若向量对象现有成员个数已超过了newsize的值,则超过部分的多余元素会丢失。(2)程序中定义了Enumeration类的一个对象
Enumeration是java.util中的一个接口类,在Enumeration中封装了有关枚举数据集合的方法。
在Enumeration中提供了方法hawMoreElement()来判断集合中是束还有其它元素和方法nextElement()来获取下一个元素。利用这两个方法可以依次获得集合中元素。
Vector中提供方法:
public final synchronized Enumeration elements()
此方法将向量对象对应到一个枚举类型。java.util包中的其它类中也大都有这类方法,以便于用户获取对应的枚举类型。1.6 栈类Stack
Stack类是Vector类的子类。它向用户提供了堆栈这种高级的数据结构。栈的基本特性就是先进后出。即先放入栈中的元素将后被推出。Stack类中提供了相应方法完成栈的有关操作。
基本方法:
public Object push(Object Hem)
将Hem压入栈中,Hem可以是任何类的对象。public Object pop()
弹出一个对象。public Object peek()
返回栈顶元素,但不弹出此元素。public int search(Object obj)
搜索对象obj,返回它所处的位置。public boolean empty()
判别栈是否为空。例1.4 StackApp.java使用了上面的各种方法。
例1.4
StackApp.java。
import java.lang.*;
import java.util.*;
public class StackApp{
public static void main(String args[]){
Stack sta=new Stack();
sta.push("Apple");
sta.push("banana");
sta.push("Cherry");
//压入的为字符串对象
sta.push(new Integer(2));
//压入的为Integer的对象,值为2
sta.push(new Float(3.5));
//压入的为Float的对象,值为3.5
System.out.println("The stack is,"+sta);
//对应栈sta
System.out.println("The top of stack is:"+sta.peek());
//对应栈顶元素,但不将此元素弹出
System.out.println("The position of object Cherry is:"
+sta.search("cherry"));
//打印对象Cherry所处的位置
System.out.print("Pop the element of the stack:");
while(!sta.empty())
System.out.print(sta.pop()+" ");
System.out.println();
//将栈中的元素依次弹出并打印。与第一次打印的sta的结果比较,可看出栈
//先进后出的特点
}
}
