7.1 Java类库的结构类库就是Java API(Application Programming Interface,应用程序接口),是系统提供的已实现的标准类的集合。在程序设计中,合理和充分利用类库提供的类和接口,不仅可以完成字符串处理、绘图、网络应用、数学计算等多方面的工作,而且可以大大提高编程效率,使程序简练、易懂。 Java类库中的类和接口大多封装在特定的包里,每个包具有自己的功能。表7.1列出了Java中一些常用的包及其简要的功能。其中,包名后面带“. *”的表示其中包括一些相关的包。有关类的介绍和使用方法,Java中提供了极其完善的技术文档。我们只需了解技术文档的格式就能方便地查阅文档。 表7.1Java提供的部分常用包
注:在使用Java时,除了java.lang外,其他的包都需要import语句引入之后才能使用。 7.2 java.lang包中的常用类 java.lang是Java语言最广泛使用的包。它所包括的类是其他包的基础,由系统自动引入,程序中不必用import语句就可以使用其中的任何一个类。java.lang中所包含的类和接口对所有实际的Java程序都是必要的。下面我们将分别介绍几个常用的类。 7.2.1 String类和StringBuffer类许多语言中,字符串是语言固有的基本数据类型。但在Java语言中字符串通过String类和StringBuffer类来处理。 1.String类Java语言中的字符串属于String类。虽然有其它方法表示字符串(如字符数组),但Java使用String类作为字符串的标准格式。Java编译器把字符串转换成String对象。String对象一旦被创建了,就不能被改变。如果需要进行大量的字符串操作,应该使用StringBuffer类或者字符数组,最终结果可以被转换成String格式。 (1)创建字符串 创建字符串的方法有多种方式,通常我们用String类的构造器来建立字符串。表6.2列出了String类的构造器及其简要说明。 表7.2 String类构造器概要
【例7.1】使用多种方法创建一个字符串并输出字符串内容。 public class StrOutput { public static void main(Sring[] args) { //将字符串常量作为String对象对待,实际上是将一个String对象赋值给另一个 String s1 = "Hello,java!"; //声明一个字符串,然后为其赋值 String s2; s2 = "Hello,java!"; //使用String类的构造器中的一个。创建一个空字符串,然后赋值给它 String s3 = new String( ); S3 = "Hello,java!"; //将字符串直接传递给String类构造器来创建新的字符串 String s4 = new String("Hello,java!"); //使用String类的构造器中的一个。 //通过创建字符数组传递给String类构造器来创建新的字符串 Char c1[ ] = { ' H', ' i', ' , ' , 'j', 'a', 'v', 'a'}; String s5 = newString(c1 ); //将字符数组子集传递给String类构造器来创建新的字符串 String s6 = new String(c1,0,2 ); System.out.println(s1); System.out.println(s2); System.out.println(s3); System.out.println(s4); System.out.println(s5); System.out.println(s6); } } 运行结果: C:/>java StrOutput Hello,java! Hello,java! Hello,java! Hello,java! Hi,java Hi (2)字符串的操作 Java语言提供了多种处理字符串的方法。表6.3列出了String类常用的方法。
表7.3 String类的常用方法
下面结合常用的方法,介绍几种典型的字符串操作。 ①字符串的比较 Java语言提供了四种字符串的比较方法,这些方法有些类似于操作符。例如,可以使用equals、equalsIgnoreCase、regionMatches和compareTo方法来实现对字符串的比较。调用形式如下: s1.equals(s2) ----- 如果s1等于s2,返回true,否则为false。 s1. equalsIgnoreCase (s2) ----- 如果s1等于s2,返回true,否则为false,忽略大小写。 s1. regionMatches(boolean ignoreCase,int toffset,s2,int ooffset,int len ) ----- 如果s1和 s2的子串相等,返回true,否则为false。其中,ignoreCase为忽略大小写设置,true为忽略大小写,false为不忽略大小写,toffset确定s1的起始偏移量,ooffset确定s2的起始偏移量,len确定子串的长度。 s1. compareTo (s2) -----如果s1 【例7.2】比较字符串。 public class StrCompare { public static void main(Sring[] args) { String s1="aaaa"; String s2="aaaa"; String s3="AAAA"; String s4="bcd"; if (s1.equals(s2)) { System.out.println("s1==s2"); } else { System.out.println("s1!=s2"); } if (s1.equalsIgnoreCase(s3)) { System.out.println(" s1= =s3 when ignoring case"); } else { System.out.println(" s1!=s3 when ignoring case"); } if (s1.regionMatches(true,0,s3,1,3)) { System.out.println(" s1= =s3 when ignoring case"); } else { System.out.println(" s1!=s3 when ignoring case"); } if (s1.regionMatches(false,0,s3,1,3)) { System.out.println(" s1= =s3 when not ignoring case"); } else { System.out.println("s1!=s3 when not ignoring case"); } if (s1.compareTo(s4)<0) { System.out.println(" s1 } else if (s1.compareTo(s4)= =0){ System.out.println("s1= =s4"); } else{ System.out.println("s1>s4"); } } } 运行结果: C:/>java StrCompare s1= =s2 s1= =s3 when ignoring case s1= =s3 when ignoring case s1!= =s3 when not ignoring case s1 ②求字符串长度 使用String类的length方法,调用形式如下: s1.length( ) ----- 返回s1的长度,其类型为int。 【例7.3】求指定字符串的长度。 public class StrLength {public static void main(Sring[] args) {String s1="Hello,Java!"; int i=s1.length(); System.out.println("字符串s1长度为"+i); } } 运行结果: C:/>java StrLength 字符串s1长度为11 ③连接字符串 可以使用两种方法将字符串连接起来:+操作符、用String类的concat方法。Concat方法的调用形式如下: s1.concat(s2) ----- 将两个字符串连接起来。 s1.concat(“字符串常量”) ----- 将字符串和字符串常量连接起来。 【例7.4】使用+和concat方法创建同一个字符串。 public class StrConcat {public static void main(Sring[] args) {String s1="Hello"; String s2=s1+","; String s3=s2.concat(" Java");! String s4=new String(" ! "); String s5=s4.concat(s4); System.out.println(" 连接而成的字符串是"+s5); } } 运行结果: C:/>java StrConcat 连接而成的字符串是Hello,Java! ④拷贝字符串 可以有四种方法将一个字符串复制到另一个字符数组或String对象中:copyValueOf、getChars、toCharArray、substring。调用形式: s1.copyValueOf(data) ----- 将数组data中的内容全部拷贝到字符串中。 s1.copyValueOf(data,int offset,int count) ----- 将数组data中以offset起始,长度为count的内容拷贝到字符串中。 s1.getChars(int strbegin,int strend, data,int offset) ----- 将s1的全部或部分内容拷贝到数组data中。其中,strbegin为字符的起始,strend 为字符的终止,offset为字符数组的起始。 data=s1.toCharArray( ) ----- 将s1中的全部内容拷贝到一个字符数组data中。 s2=s1.substring(int strbegin) ----- 将s1中以stregin起始的内容拷贝到s2中。 s2=s1.substring(int strbegin,int strend) ----- 将s1中以stregin起始,以strend结束之间的内容拷贝到s2中。 【例7.5】拷贝字符串。 public class StrCopy {public static void main(Sring[] args) { String s1=new String( ); char data[ ]={ 'a', 'b', 'c', 'd', 'e', 'f'}; s1=s1.copyValueOf(data); System.out.println(" s1="+s1); s1=s1.copyValueOf(data,2,3); System.out.println(" s1="+s1); s1.getChars(1,2, data,0) System.out.println(" data="+data); data=s1. toCharArray( ); System.out.println(" data="+data); String s2=new String( ); String s3=new String( ); s2=s1.substring(0); System.out.println(" s2="+s2); s3= s1.substring(1,2); System.out.println(" s3="+s3); } } 运行结果: C:/>java StrCopy s1=abcdef s2=cde data=decdef data=cde s2=cde s3=de ⑤在字符串中查找字符和子串 在字符串中查找字符和子串,确定它们的位置,有几种常用的方法:charAt、indexOf、lastIndexOf。调用形式如下: s1.chatAt(int index)--------返回s1中index所对应的字符。其中,index是下标号。 s1. indexOf (int char)--------返回s1中字符char在字符串中第一次出现的位置。 s1. lastIndexOf (int char)--------返回s1中字符char在字符串中最后一次出现的位置。 s1. indexOf (s2)--------返回s2在s1中第一次出现的位置。 s1. lastIndexOf (s2)--------返回s2在s1中最后一次出现的位置。 【例7.6】查找字符和子串。 public class StrSearch {public static void main(Sring[] args) { String s1="Javav"; char c=s1.charAt(2); System.out.println("c=",+c); int i=s1.indexOf('a'); System.out.println("fistchar=",+i); int j=s1.lastIndexOf('a'); System.out.println("lastchar=",+j); i= s1.indexOf("av"); System.out.println("fiststring=",+i); j=s1.lastIndexOf("av"); System.out.println("laststring=",+j); } } 运行结果: C:/>java StrSearch c=v firstchar=1 lastchar=3 firststring=1 laststring=3 ⑥修改字符串 修改字符串的常用方法有:replace、toLowerCase、toUpperCase、trim。调用形式如下: s1.replace(oldchar,newchar)--------用新字符newchar替代旧字符oldchar,若指定字符不存在,则不替代。 s1.toLowerCase( )--------将s1中的所有大写字母转换为小写字母。 s1.toUpperCase( )-------- 将s1中的所有小写字母转换为大写字母。 s1.trim( )--------删除s1中的首、尾空格。 【例7.7】修改字符串。 public class StrModify {public static void main(Sring[] args) { String s1="Java"; s1=s1.replae('a', 'b'); System.out.println("s1=",+s1); String s2=s1.toLowerCase( ); String s3=s1. toUpperCase ( ); System.out.println("s2=",+s2); System.out.println("s3=",+s3); s2= s1.trim( ); System.out.println("s2=",+s2); } } 运行结果: C:/>java StrModify s1= Jbvb s2= jbvb s3= JBVB s2= jbvb 缓冲字符串类StringBuffer与String类相似,它具有String类的很多功能,甚至更丰富。它们主要的区别是StringBuffer对象可以方便地在缓冲区内被修改,如增加、替换字符或子串。与Vector对象一样,StringBuffer对象可以根据需要自动增长存储空间,故特别适合于处理可变字符串。当完成了缓冲字符串数据操作后,可以通过调用其方法StringBuffer.toString( )或String构造器把它们有效地转换回标准字符串格式。 (1)创建StringBuffer对象 可以使用StringBuffer类的构造器来创建StringBuffer对象。表6.4 是StringBuffer的构造器及其简要说明。 表6.4StringBuffer类构造器概要 构造器 说明 StringBuffer( ) 构造一个空的缓冲字符串,其中没有字符,初始长度为16个字符的空间 StringBuffer(int length) 构造一个长度为length的空缓冲字符串 StringBuffer(String str) 构造一个缓冲字符串,其内容初始化为给定的字符串str,再加上16个字符的空间 【例7.8】用多种方法创建StringBuffer对象。 public class StrBufferSet {public static void main(Sring[] args) { StringBuffers1=new StringBuffer( ); s1.append("Hello,Java!"); System.out.println("s1=" +s1); StringBuffers2=new StringBuffer(10 ); S2.insert(0, "Hello,Java!"); System.out.println("s2="+s2); StringBuffers3=new StringBuffer("Hello,Java!"); System.out.println("s3="+s3); } } 运行结果: C:/>java StrBufferSet s1=Hello,Java! s2=Hello,Java! s3=Hello,Java! (2)StringBuffer类的常用方法 StringBuffer类是可变字符串,因此它的操作主要集中在对字符串的改变上。 ①为StringBuffer的对象插入和追加字符串 可以在StringBuffer对象的字符串之中插入字符串,或在其之后追加字符串,经过扩充之后形成一个新的字符串,方法有:append和insert,调用形式如下: s1.append(s2)--------将字符串s2加到s1之后。 s1.insert(int offset,s2)--------在s1从起始处offset开始插入字符串s2。 append和insert都有多个重载方法,这里不一一赘述。关于append和insert方法的使用见例6.8 。 ②获取和设置StringBuffer对象的长度和容量 获取和设置StringBuffer对象的长度和容量的方法有:length、capacity、setlength,调用形式如下: s1.length( )--------返回s1中字符个数。 s1. capacity ( )--------返回s1的容量,即内存空间数量。通常会大于length( ) s1. setlength (int newLength )--------改变s1中字符的个数,如果newLength大于原个数,则新添的字符都为空("");相反,字符串中的最后几个字符将被删除。 【例7.9】显示确定字符串的长度和容量,并改变字符串的长度。 public class StrLen {public static void main(Sring[] args) { StringBuffers1=new StringBuffer("Hello,Java!"); System.out.println("The length is"+s1.length( )); System.out.println("The allocated length is"+s1.capacity( )); s1.setlength(100); System.out.println("The new length is"+s1.length( )); } } 运行结果: C:/>java StrLen The length is11 The allocated length is22 The new length is100 ③读取和改变StringBuffer对象中的字符 读取StringBuffer对象中的字符的方法有:charAt和getChar,这与String对象方法一样。在StringBuffer对象中,设置字符及子串的方法有:setCharAt、replace;删除字符及子串的方法有:delete、deleteCharAt。调用形式如下: s1.setCharAt(int index,char ch)--------用ch替代s1中index位置上的字符。 s1.replace(int start,int end,s2)--------s1中从start(含)开始到end(不含)结束之间的字符串以s2代替。 s1.delete(int start,int end)--------删除s1中从start(含)开始到end(不含)结束之间的字符串。 s1.deleteCharAt(int index)------删除s1中index位置上的字符。 【例7.10】改变字符串的内容。 public class StrChange {public static void main(Sring[] args) { StringBuffers1=new StringBuffer("Hallo,Java!"); s1.setCharAt(1, 'e'); System.out.println(s1); s1.replace(1,5, "i"); System.out.println(s1); s1.delete(0,3); System.out.println(s1); s1.deleteCharAt(4); System.out.println(s1); } } 运行结果: C:/>java StrChange Hello,Java! Hi,Java! Java! Java System类是一个特殊类,它是一个公共最终类,不能被继承,也不能被实例化,即不能创建System类的对象。 System类功能强大,与Runtime一起可以访问许多有用的系统功能。System类保存静态方法和变量的集合。标准的输入、输出和Java运行时的错误输出存储在变量in,out和err中。由System类定义的方法丰富并且实用。System类中所有的变量和方法都是静态的,使用时以System作为前缀,即形如“System.变量名”和“System.方法名”。 System类包含三个使用频繁的公共数据流,分别是:标准输入(in)、标准输出(out)、标准错误输出(err)。 ① public static final InputStream in--------标准输入。 这个属性是InputStream类的一个对象,它是未经包装的原始Input Stream,读取System.in之前应该先加以包装。可以通过read()方法读取字节数据。 ② public static final PrintStream out--------标准输出。 ③ public static final PrintStream err---------标准输出。 out和err都已经被包装成PrintStream对象,所以可以直接使用System.out和System.err。可以通过方法print()、println()或write()方法很方便地完成各种数据类型的输出。out与err使用上的不同是: System.out用于输出普通信息,out的输出一般需要缓存;System.err一般情况下用来打印错误信息,不需要缓存,快速显示紧急信息。 关于InputStream类和PrintStream类将在java.io包中介绍。 System类有一些有用的方法,这些方法用于处理运行环境。下面简单介绍几个方法及其功能。 (1)获取当前时间 使用currentTineMillis( )可以记录程序执行的时间,这是一个特别有意义的用法。currentTineMillis( )方法返回自从1970年1月1日午夜起到现在的时间,时间单位是毫秒。如果要记录程序中一段有问题程序的运行时间,可以在这段程序开始之前调用currentTineMillis( )方法存储当前时间,在这段程序结束处再次调用currentTineMillis( )方法。执行该段程序所花费的时间为其结束时刻的时间值减去其开始时刻的时间值。下面的程序段可以用来估计一下执行某个循环所占用的时间: long startTime=System.currenTimerMillis( );//记录循环开始时间 int sum=0; for(int i=0;i<100000;i++){ sum+=i; } long endTime=System.currentTimeMillis( );// 记录循环结束时间 System.out.Println("time: "+(endTime-startTime)+ "milliseconds. "); 注意:虽然使用cuttentTimeMillis()方法可以计算出当前的日期和时间,但是获取当前日期和时间最好使用java.util中的Date类。 (2)快速复制数组 使用arraycopy()方法可以将一个任意类型的数组快速地从一个地方复制到另一个地方。这比使用循环编写的程序要快得多。调用形式为: System.arraycopy(a1,int sourceStart,a2,int targetStart,int size)------将数组a1从下标sourceStart开始,长度为size的元素依次复制到数组a2的以targetStart为起始的单元中。 【例7.11】用arraycopy()方法复制两个数组。 class CopyArray {static byte array1[ ]={97,98,99,100,101}; static byte array2[ ]={102,102,102,102,102}; public static void main(Sring[] args) { System.out.println(" array1="+new String(array1)); System.out.println(" array2="+new String(array2)); System.arraycopy(array1,0,array2,0,array1.length); System.out.println(" array1="+new String(array1)); System.out.println(" array2="+new String(array2)); System.arraycopy(array1,0,array1,1,array1.length-1); System.arraycopy(array2,1,array2,0,array2.length-1); System.out.println(" array1="+new String(array1)); System.out.println(" array2="+new String(array2)); } } 运行结果: C:/>java CopyArray array1=abcde array2=fffff array1=abcde array2= abcde array1=aabcd array2=bcdee (3)退出虚拟机 在用户的程序还未执行完之前,强制关闭Java虚拟机的方法是exit(): Public static void exit(int exitCode) 关闭虚拟机的同时把状态信息exitCode传递给操作系统,exitCoded非零时,表示非正常退出。 (4)强制垃圾收集 垃圾收集器一般情况下运行于后台,并自动地收集已不使用了的内存。使用gc()方法可强制垃圾收集器启动: public static void gc() 可以通过调用System.getProperty()方法来获得不同环境属性的值。例如下面的程序显示当前用户目录的路径: class PlayUserDir{ public static void main(String[ ] args){ System.out.println(System.getProperty(" user.dir")); } } 可以通过setProperty( )方法设置系统属性的值: public static String setProperty(String key,String value); 其中,key为键名,value为键值。 Math类提供了用于几何学、三角学以及几种一般用途方法的浮点函数,来执行很多数学运算。 doubleE--------常量e(2.7182818284590452354) doublePI--------常量pi(3.14159265358979323846) Math类定义的方法是静态的,可以通过类名直接调用。下面简要介绍几类常用的方法。 ①三角函数 public static double sin(double a)------三角函数正弦。 public static double cos(double a)------三角函数余弦。 public static double tan(double a)------三角函数正切。 public static double asin(double a)------三角函数反正弦。 public static double acos(double a)------三角函数反余弦。 public static double atan(double a)------三角函数反正切。 ② 指数函数 public static double exp(double a)------返回ea的值。 public static double log(double a)------ 返回lna的值。 public static double pow (double y,double x)------ 返回以y为底数,以x为指数的幂值。 public static double sqrt(double a)------ 返回a的平方根。 ③ 舍入函数 public static intceil(double a)------- 返回大于或等于a的最小整数。 public static intfloor(double a)------- 返回小于或等于a的最大整数。 以下三个方法都有其它数据类型的重载方法: public static intabs(int a)------- 返回a的绝对值。 public static intmax(int a,int b)------- 返回a和b的最大值。 public static intmin(int a,int b)------- 返回a和b的最小值。 ④其它数学方法 public static doublerandom( )------ 返回一个伪随机数,其值介于0和1之间。 public static doubletoRadians(doubleangle )------ 将角度转换为弧度。 public static doubletoDegrees (doubleangle)------ 将弧度转换为角度。 java.util是Java语言中另一个使用广泛的包,它包括集合类、时间处理模式、日期时间工具等各种常用工具。 Java的集合类是java.util包中的重要内容,它允许以各种方式将元素分组,并定义了各种使这些元素更容易操作的方法。集合类中存放的是对象,不同的集合类有不同的功能和特点,适合不同的场合,用以解决一些实际问题。 下面我们将介绍集合类中的几个常用类的使用。 Java的数组具有很强的功能,但它并不总是能满足我们的要求。数组一旦被创建,它的长度就固定了。但是,有时我们在创建数组时并不确切地知道有多少项需要加进去。解决这一问题的办法是,创建一个尽可能大的数组,以满足要求,但这势必会造成空间的浪费。Java提供了一个好的办法:使用java.util包中的向量类Vector。 简单地说,Vector是一个动态数组,它可以根据需要动态伸缩。另外,Vector类还提供了一些有用的方法,如增加和删除元素的方法,而这些操作在数组中一般来说必须手工完成。 Vector类提供了三个属性,四个构造器和多种方法,下面分别做以介绍: protected int capacityIncrement--------当向量的大小超过容量时,向量容量的增长量。 protected int elementCount--------这个Vector对象中的组件数。 protectedObjected[ ] elementData--------存储向量的组件的数组缓冲区。 Vector( )--------构造一个空向量。 Vector(Collection c )--------构造一个包含给定集合中的元素的向量。 Vector(int initialCapacity )--------构造一个具有给定的初始容量的空向量。 Vector(int initialCapacity, int capacityIncrement )-------- 构造一个具有给定的初始容量和容量增量的空向量。 ① 向向量中添加对象 向一个向量中添加新对象有两种情况,可以用Vector提供的两种不同方法来实现: void addElement(Object obj)-------- 在向量的最后增加一个元素。 void insetElementAt(Object obj,int index)-------- 在向量的指定位置插入一个元素。 ② 从向量中删除对象 从向量中删除对象有三种情况,可以用Vector提供的三种不同方法来实现: void removeAllElement( )--------删除向量中的所有对象。 void removeElement(Object ob)--------删除向量中一个指定的对象(仅删除第一次出现的对象)。 void removeElementAt( int index)--------删除向量中一个指定位置上的对象。 ③ 搜索向量中的对象 有时我们需要得到向量中特殊位置上的对象或判断向量中是否包含某个对象,可以使用如下的方法: Object firstElement( )--------返回这个向量的第一个对象。 Object lastElement( )--------返回这个向量的最后一个对象。 Object ElementAt(int index )--------返回这个向量中指定位置的对象。 Boolean contains(Object elem)--------如果这个对象在这个对象中,则返回true。 ④获取向量的基本信息 int capacity( )--------返回这个向量的当前容量。 int size( )-------- 返回这个向量的对象个数。 【例7.12】使用Vector类的示例。 class VectorTest{ public static void main(Sring[] args){ Vector vec=new Vector(3); System.out.println(" old capacity is"+vec.capacity()); vec.addElement(new Integer(1)); vec.addElement(new Integer(2)); vec.addElement(new Integer(3)); vec.addElement(new Float(2.78)); vec.addElement(new Double(2.78)); System.out.println(" new capacity is"+vec.capacity()); System.out.println(" new size is"+vec.size()); System.out.println(" first item is"+(Integer)vec.firstElement()); System.out.println(" last item is"+(Float)vec.lasttElement()); if(vec. Contains(new Integer(2))) System.out.println(" found 2"); vec. removeElementAt(1); if(vec.Contains(new Integer(2))){ System.out.println(" found 2"); else System.out.println(" after deleting not found 2"); } } 运行结果: C:/>java VectorTest old capacity is3 new capacity is6 new size is5 first item is1 last item is2.78 found 2 after deleting not found 2 Stack是Vector的一个子类,它实现标准的后进先出堆栈。Stack 仅仅定义了创建空堆栈的默认构造函数。Stack包括了由Vector定义的所有方法,同时增加了几种它自己定义的方法,介绍如下: boolean empty( )--------如果堆栈是空的,则返回true,当堆栈包含元素时,返回false。 Object peek( )-----------返回位于栈顶的元素,但是并不在堆栈中删除它。 Object pop( )------------返回位于栈顶的元素,并在进程中删除它。 Object push (Object element )---------将element压入堆栈,同时也返回element。 int search(Object element)---------在堆栈中搜索element,如果发现了,则返回它相对于栈顶的偏移量。否则,返回-1。 【例7.13】向堆栈中添加元素并弹出。 import java.util.* classStackTest{ public static voidmain(Sring[] args){ Stack stack1=new Stack();//构造一个空堆栈stack1 try { stack1.push(new Integer(0)); stack1.push(new Integer(1)); stack1.push(new Integer(2)); stack1.push(new Integer(3)); stack1.push(new Integer(4)); System.out.println((Integer)stack1.pop()); System.out.println((Integer)stack1.pop()); System.out.println((Integer)stack1.pop()); System.out.println((Integer)stack1.pop()); System.out.println((Integer)stack1.pop()); } catch(EmptyStackException e){ } } } 运行结果: C:/>java StackTest 4 3 2 1 0 前面讲到的集合类是通过下标来确定元素的位置,集合中的对象有一定的顺序,而Hashtable(散列表)却不同,它通过另一种方式来确定对象的位置。它是映射集合的一种实现,提供了将一个对象与另一个对象相关联的方法。 Hashtable是Dictionary类的子类,Dictionary类是抽象类,与查字典操作类似,它要达到通过一个键(key)来查找元素的目的。Hashtable类也是通过键来查找对象,如何确定这个键值呢?首先,散列表为每个对象计算出一个整数,称为散列码,每个对象与其散列码一一对应;然后,用散列码与对象个数进行取模运算,计算出相对应的键。散列表中的对象就是通过这种方式一一放入的,所以在查询对象时,用同样的方式就可以快速定位对象在散列表中的位置。 Hashtable不仅实现了父类的方法,还有自己的方法,如conrainsKey(Object key)。 下面介绍几个常用的方法: Object put(Object key, Object value)--------将关键字和值插入散列表中。如果key不在散列表中,返回null。如果key已存在于散列表中,则返回与key相连的前一个值。 Object get(Object key)--------返回包含与key相关联的值的对象。如果key不在散列表中,则返回一个空对象。 Object remove(Object key)--------删除key及其相应的值,返回与key相关联的值。如果key不在散列表中,则返回一个空对象。 boolean conrainsKey(Object key)--------用来检查形参对象是否是一个散列表的键,是则返回true,否则返回false。 另外,size()方法返回表中元素的个数,isEmply()方法判断表中是否包含有元素。 作为应用散列表的一个典型例子,可考虑用一个程序来检验Java的Math.random()方法的随机性到底如何。在理想情况下,它应该产生一系列完美的随机分布数字。但为了验证这一点,我们需要生成数量众多的随机数字,然后计算落在不同范围内的数字多少。散列表可以极大简化这一工作,因为它能将对象同对象关联起来(此时是将Math.random()生成的值同那些值出现的次数关联起来)。 【例7.14】用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} Java技术文档描述代码的工作原理,可以向程序员提供信息,是需要经常查看的资料。这一节我们将介绍如何查看javaDOC中的类库。 可以从Sun公司的网站上下载Java文档。在下载完j2sdk-1_4_2-doc后,找到它下面的docs文件夹,打开其中的index文件(HTML文件),找到“API & Language Documentation”下的“Java 2PlatformAPI Specification”,然后选择需要查看的那个包,进而查看类、接口等内容。或者直接进入docs文件夹下的api文件夹,打开index(HTML文件),也可进入选择包的界面。 选择一个包后,可以看到包的名称及简单描述,然后是包中的内容,分为interface summary、class summary、exception summary和error summary等(当然包中如果没有某一方面内容,就不包含),如果想看包中各类的继承结构,可以选择最上面的菜单中的tree,就可以了解包中的总体结构。 当选择一个类进入后,可以看到如下的内容(以Double类为例说明): java. lang//包名 Class Double//类名 java. lang. Object//继承结构:java. lang包中的Double类的直接父类 |//是java. lang中的Number类, +--java. lang. Number | +--java. lang. Double All Implemented Interfaces: Comparable, Serializable 然后是类头定义和说明,以及源于哪个版本: public final class Double extends Number implements Comparable The Double class wraps a value of the primitive type double in an object. An object of type Double contains a single field whose type is double. In addition, this class provides several methods for converting a double to a String and a string to a double, as well as other constants and methods useful when dealing with a double. Since: JDK1.0 See Also: serialized Form 然后就是属性、方法、构造函数的概述表(summary),最后是属性、方法、构造函数的详细说明。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
小结 Java语言的内核非常小,其强大的功能主要由类库(Java API,应用程序接口)体现。从某种意义上说,掌握Java的过程也是充分利用Java类库中丰富资源的过程。 String类和StringBuffer类用来完成字符串处理,它们都具有多个构造器(构造函数)。通常使用String类来定义固定长度字符串。当字符串长度空间不确定时,应该使用StringBuffer类,它具有更丰富的功能。 公共最终类System和数学类Math中所有的变量和方法都是静态的,可以通过类名直接调用。 Java的集合类是java.util包中的重要内容。常用的有向量类Vector、堆栈类Stack、散列表类Hashtable。更多有关类库的介绍和使用方法,需要查阅Java技术文档。 |