游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2025|回复: 0

JAVA的集合类实用介绍1wxh zt

[复制链接]

1367

主题

1993

帖子

2118

积分

金牌会员

Rank: 6Rank: 6

积分
2118
发表于 2005-3-6 01:01:00 | 显示全部楼层 |阅读模式
      集合类是用来存放某类对象的,我们以前学过的数组应该是一个最典型的集合类,但为了便于区分,我们下面所说的集合类中不包括数组。数组是有固定长度的,在定义数组的时候,就需要确定这个数组的内存空间,但很多时候我们不能确定需要存放多少元素,这时数组就显得很不方便,这时就需要用集合类,如Vector,Hashtable,Stack和Bitset等。
集合类有一个共同特点,就是他们只容纳对象,这一点和数组不同,数组可以容纳对象和简单数据。如果集合类中想使用简单数据类型,又想利用集合类的灵活性,可以把简单数据类型数据变成该数据类型类的对象,然后放入集合中处理,但这样执行效率会降低。
另外,集合类容纳的对象都是Object类的实例,一旦把一个对象置入集合类中,它的类信息将丢失,也就是说,集合类中容纳的都是指向Object类对象的指针。这样的设计是为了集合类有通用性,因为Object类是所有的祖先,所以可以在这些集合中存放任何类而不受限制,当然这也带来了不便,就是是用集合成员之前必须对它重新造型。
还有操作数组和集合类时的系统自动检查下标是否越界,如果出现越界,就会自动抛出RuntimeException类的例外,程序中可以没有越界检查。
我们将按照JDK的版本分两部分来讲解Java的集合类。
                     9.2 源集合类
    在JDK1.1中Java提供了几种非常简单易用的集合类,尽管在JDK的新版本中有更丰富的类可以使用,这些类在目前的Java应用中还是非常常见的。
9.2.1 数组
    我们在以前的数组中只是存放简单数据,而没有存放过对象,我们在下面的两个例子中看看这两种情况的不同以及如何传递对象数组。
例9.1 数组中容纳对象和简单数据
这个程序中把对象和简单数据分别作为数组的元素,然后对他们分别操作,表现他们的不同,它们各自的操作注意点在注释中给出。
ArraySize.java的源文件如下:
class Honeybee{}
public class ArraySize{
public static void main(String[] args){
Honeybee[] a;
Honeybee b[]=new Honeybee[5];
Honeybee[] c=new Honeybee[4];
for(int i=0;i<c.length;i++)
c=new Honeybee();
Honeybee[] d={
new Honeybee(),new Honeybee(),new Honeybee()
};
System.out.println("a.length=" +b.length);
for(int i=0;i<b.length;i++)
System.out.println("b[" + i +"]="+b);
System.out.println("c.length="+c.length);
System.out.println("d.length="+d.length);
a=d;
System.out.println("a.length="+a.length);
a=new Honeybee[]{
new Honeybee(),new Honeybee()
};
System.out.println("----------");
int[] e;
int f[]=new int[5];
int[] g=new int[4];
for(int i=0;i<g.length;i++)
g=i*i;
int[] h={11,47,93};
System.out.println("f.length="+e.length)
for(int i=0;i<f.length;i++)
System.out.println("f["+i+"]="+f[I]);
System.out.println("g.length="+g.length);
System.out.println("h.length="+h.length);
e=h;
System.out.println("e.length="+e.length);
e=new int[]{1,2};
System.out.println("e.length="+e.length);
}
}
程序的输出如下:
b.length=5
b[0]=null
b[1]=null
b[2]=null
b[3]=null
b[4]=null
c.length=4
d.length=3
a.length=3
a.length=2
----------
f.length=5
f[0]=0
f[1]=0
f[2]=0
f[3]=0
f[4]=0
g.length=4
h.length=3
e.length=3
e.length=2
    上面的程序中我们用同样的格式设计了两种数组:对象数组和简单数据类型数组,以进行比较。其中数组a只是初始化成一个null的对象名(指针),此时,编译器会禁止我们对这个指针进行任何实际操作。数组b被初始化成指向由Weeble类对象构成的一个数组,但那个数组里实际并未放置任何Weeble对象,所以数组b的元素都是空指针,不能直接使用,然而,我们仍然可以查询那个数组的大小,因为b指向的是一个合法对象。这个程序这哦功能还用到对象间的赋值,对象间赋值转递的是指针。关于对象数组的创建Java1.0和Java1.1有些不同,Java1.1允许先定义,后创建,Java1.0规定定义时创建,程序中的d就是Java1.0的格式。Java1.1加入了一种新的数组初始化语法:
a=new Honeybee[]{new Honeybee(),new oneybee()};
这种语法可以直接用作方法的参数,如方法f()需要转递一个对象数组,我们可以这样写:
f(a);
也可以这样:
f(new Honeybee[]{new Honeybee(),new oneybee()});
9.2.2 Vector类
   该类实现了可变数组。和数组一样,它的元素可通过下标进行访问。Vector类的对象通过capacity和capaacityIncrement两个值来改变集合的容量,capacity指示集合最多能容纳的元素个数,capacityIncrement指示每次增加多少容量而不是一个一个增加的。因此,capacity通常大于等于实际的元素个数。Vector类实现类接口List,所以它也成为Collection结构的一部分。这个类有3个属性、多个构造函数和许多其它方法。下面列举几个方法:
●void addElement(Object obj)——在集合的最后增加一个元素
●void add(int index,Object element)——在指定位置增加一个元素
●Object elementAt(int index)——返回指定位置的元素
●void insertElementAt(Object obj,int index)——在指定位置插入元素
●void removeElementAt(int index)——删除指定位置的元素
●int catacity()——返回当前容量
●int size()——返回集合的元素个数
    这几个方法反映Vector类的几个基本操作。
在集合中的对象必须是同类的,否则程序执行时将抛出例外,不过这并不影响程序的编译。
例9.2 集合中元素必须是同类的对象
这个程序中定义3个类,一个是主类,另两个是Cat和Dog,然后我们把它们的对象放入同一个Vector中,看结果如何。
CatsAndDogs.java的源文件如下:
import java.util.Vector;
class Cat{
private int catNumber;
Cat(int i){
catNumber=i;
}
void print(){
System.out.println("Cat #"+catNumber);
}
}
class Dog{
private int dogNumber;
Dog(int i){
dogNumber=i;
}
void print(){
System.out.println("Dog #"+dogNumber);
}
}
public class CatsAndDogs{
public static void main(String[] args){
Vector cats=new Vector();
for(int i=0;i<7;i++)
cats.addElement(new Cat(i));
cats.addElement(new Dog(7));
for(int i=0;i<cats.size();i++)
((Cat)cats.elementAt(i).print();
}
}
程序的结果如下:
Cat #0
Cat #1
Cat #2
Cat #3
Cat #4
Cat #5
Cat #6
Exception in thread “main”java.lang.ClassCastExceptionog
at CatsAndDogs.main(CatsAndDogs.java:31)
   这个程序只有在执行((Cat)cats.elementAt(7)).print();的时侯抛出例外。在这个程序中也看到了重新造型的格式:(Cat)cat.elementAt(i),因为一个集合的元素是一个Object类的对象,所以必须把它强制转换成Cat类的对象进行操作。读者可能会想,能不能把元素转换成Dog类,答案是肯定的,把程序中的最后两句换成如下形式,就能把最后一个元素输出。
for(int i=cats.size()-1;i>=;i--)
((Dog)cats.elementAt(i)).print();
这时的输出结果为:
Dog #7
Exception in thread”main” java.lang.ClassCastException:Cat
at CatsAndDogs.main(CatsAndDogs.java:31)
   程序中我们用到了size()这个方法来确定元素的个数,其实有另一个方法可以让程序自动检查元素的类型以及集合的最后一个该类型元素,这就是Enumeration,它是一个简单的反复器,它能实现对集合的遍历。实现枚举的对象必须通过Vector类的方法elements()来创建,这个方法返回反映当前集合内容的实现枚举的对象。
我们还需要对toString()方法作一个说明,它不仅返回Vector类集合的信息,而且返回每个元素的信息。
9.2.3 Bitset类
    这个类实际是由“二进制位”构成的一个Vector,即这个Vector集合的元素都是false或true,默认值都为false.如果希望高效率的保存大量“开-关”信息,就应使用BitSet,两个Bitset类对象可以进行逻辑的与、或、异或等运算。
此外,BitSet的最小长度是一个长整数的长度:64位,这意味着假如我们准备保存比他更小的数据,如8位数据,那么Bitset就显得浪费了。所以最好创建自己的类,用它容纳自己的标志位。
它有以下几个特殊的方法:
●public void and(Bitset set)——进行逻辑运算
●public int length()——有效逻辑位的位数
●public int size()——返回集合中的元素个数,最小为64
●public void set(int bitIndex)——把指定位置的值置为true
●public void clear(int bitIndex)——把指定位置的值置为false
●public Boolean get(int bitIndex)——得到制定位置的值
下面来熟悉Bitset类的用法
例9.3 使用Bitset类
Bits.java的源文件如下:
import java.util.*;
public class Bits{
public static void main(String[] args){
Random rand=new Random();
byte bt=(byte)rand.nextInt();
BitSet bb=new BitSet();
for(int i=7;i>=0;i--)
if(((1<<i)&bt) !=0)
bb.set(i);
else
bb.clear(i);
System.out.println("byte value:"+bt);
printBitSet(bb);
System.out.println("logical size:"+bb.length());
short st=(short)rand.nextInt();
BitSet bs=new BitSet();
for(int i=15;i>=0;i--)
if(((1<<i)& st) !=0)
bs.set(i);
else
bs.clear(i);
System.out.println("short value:"+ st);
printBitSet(bs);
System.out.println("logicalsize:"+bs.length());
int it=rand.nextInt();
BitSet bi=new BitSet();
for(int i=31;i>=0;i--)
if(((1<<i)& it) !=0)
bi.set(i);
else
bi.clear(i);
System.out.println("int value:"+ it);
printBitSet(bi);
System.out.println("logical size:"+bi.length());
BitSet b127=new BitSet();
b129.set(127);
System.out.println("set bit 127:"+ b127);
b255.set(255);
System.out.println("set bit 255:"+ b255);
BitSet b1023=new BitSet(512);
b1023.set(1024);
System.out.println("set bit 1023:"+ b1023);
}
static void printBitSet(BitSet b){
System.out.println("bits:"+ b);
String bbits=new String();
for(int j=0;j<b.size();j++)
bbits +=(b.get(j)? "1":"0");
System.out.println("bit pattern:"+ bbits);
}
}
   这个程序每次执行时有不同的结果,读者可以自己执行一下这个程序,看看输出结果。以上的程序输出的二进制形式都是64位,集合表示形式就是把置为1的位置用一个集合表示,如127表示为{0,1,2,3,4,5,6}。程序中的b129.set(127)是将第128位的值置为1。
9.2.4 Stack类
    Stack类是Vector类的子类,它是一个“后入先出”的集合。Stack的意思就是堆栈,堆栈就象一个桶,只有一个口,放入和取出都用这个口,最后放入的东西能最先拿出,最先放入的只能最后拿出。通常在堆栈中存入数据称为“压入”,取出数据成为“弹出”。由于压入和弹出都在堆栈口进行,所以位置很确定,这和其他集合不同。和其他所有Java集合一样,我们压入和弹出的都是对象,所以必须对自己弹出的东西进行造型。
这个类增加了5个方法:
●public Object push(Object item)——把形参对象压入堆栈
●public Object pop()——弹出第一个对象
●public Object peek()——并不取出的情况下,看定一个对象
●public boolean empty()——是否为空
●public int search(Object o)——检查第一个出现形参对象的位置
下面是一个简单堆栈的例子:
例9.4 堆栈类的使用
Stacks.java的源文件如下:
import java.util.*;
public class Stacks{
static String[] months={"January","February","March","April","May","June","July",
"August","September","October","November","December"
};
public static void main(String[] args){
Stack stk=new Stack();
for(int i=0;i<months.length;i++)
stk.push(months + " ");
System.out.println("stk="+ stk);
stk.addElement("The last line");
System.out.println("element 5="= stk.elementAt(5));
System.out.println("popping elements:");
while(!stk.empty())
System.out.println(stk.pop());
}
}
其运行结果如下:
stk=[January,February,March,April,May,June,July,August,September,

October,November,December]
element 5=June
popping elements:
The last line
December
November
October
September
August
July
June
May
April
March
February
January
从这个程序的结果可以清楚的看到,先压入的后弹出,这个类的对象也可以使用Vector类的方法,如addElement()和elementAt()等。
9.2.5 Hashtable类
    我们知道前面讲到的集合类都是通过下标来确定元素位置的,集合中的元素有一定的顺序,而Hashtable类却不一样,它通过另一种途径来确定它的元素位置,它没有序列的概念,它通过索引来查找对象。
这个类是字典类的子类,字典类是抽象类,它达到的目的是通过一个键来查找元素,这和实际的字典以及相似。该抽象类有许多方法,size()告诉我们其中包含了多少元素,isEmpty()判断是否包含了元素,put添加一个值,并将其同一个键关联起来,get(Object key)获得与某个键对应的值,而remove(Object Key)用于从列表中删除“键-值”对。还可以使用枚举技术,keys()产生对键的一个枚举,而elements()产生对所有值的一个枚举。
Hashtable类不仅实现父类的方法,还有自己的方法,下面这个方法就是用来检查形参对象是否是一个散列表的键:
public boolean containsKey(Object key)
下面是一个应用散列表的一个例子,用它检验Java的Math.random()方法的随机性到底如何。在理想情况下,它应该产生一系列完美的随机分布数字。但为了验证这一点,我们需要生成数量众多的随机数字,然后计算落在不同范围内的数字量。散列表可以极大简化这一工作,因为它能将两个对象关联起来。下面的程序将随机整数对应在0-20之间,然后生成10000个随机数,看他们在0-20间的分布情况。
例9.5 用Hashtable来检查随机数的随机性
Statistics.java的源文件如下:
import java.util.*;
class Counter{
int i=1;
public String toString(){
return Integer.toString(i);
}
}
public class Statistics{
public static void main(String[] args){
Hashtable ht=new Ha****able();
for(int i=0;i<10000;i++){
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);
}
}
程序的某一次运行结果如下:
{19=520,18=501,17=520,16=493,15=464,14=517,13=502,12=502,11=499,10=516,9=504,8=526,7=488,6=488,5=489,4=471,3=514,2=495,1=493,0=498}
虽然每次运行结果都不同,但都能显示0-20之间的随机产生的概率基本一样。
这个程序中我们建立一个Hashtable表ht,其中的“键-值”对是随机数(r)与统计数(Counter.i)其中的随机数是键,统计数是值。
         9.3 新集合类
    Java1.2开始有一个庞大的集合体系,它用来完成各种集合和集合操作,以上介绍的Vector、Hashtable、Stack等都被包括这个体系中。我们在前面讲到的枚举被反复器代替,不过只是名称不一样,功能仍然没变。产生反复器的方法是iterator(),这和elements()也不同,反复器内的方法名称也发生了变化,haNext()代替了hasMoreElement(),而next()代替了nextElement(),并且添加了一个名为remove()的新方法。
事实上这个集合族中分两个部分。一个是Collection系,它是一下标访问元素的集合,它实际含有List和Set两个组件。另一个是Map系,它是一种映射,通过键来访问元素的集合,另外,Map也可以产生Collection对象,把“键-值”对分开,所有的键可以形成一个Collection,所有的值也可以形成一个Collection。
下面我们分5个部分分别介绍Collection,List,Set,Map以及排序、查找工具。
9.3.1 Collection
    Collection就是真实意义上的集合,和数学中的集合一样,它不保证其中的元素有固定的顺序。下面就是Collection的所有方法,其中许多方法很容易理解。
●public int size()
●public boolean isEmpty()
●public boolean contain(Object o)——是否含有形参对象
●public Iterator iterator()——产生一个反复器,其中包含了该collection对象中所有的元素,类似于一个枚举类型的对象
●public Object[] toArray()——返回一个包含所有元素的对象数组
●public Object[] toArray(Object[]a)把所有元素放入a[]中
●public boolean add(Object o)集合中加入对象,成功时返回true
●public boolean remove(Object o)
●public boolean containsAll(Collection c)——判断c是否为子集
●public boolean addAll(Collection c)
●public boolean removeAll(Collection c)——清空指定集合
●public boolean retainAll(Collection c)删除所有c中没有的元素
●public void clear()——清空集合
●public boolean equals(Object o)——比较两个对象是否相同
●public int hashCode()——获取集合的hashcode
例9.6 Collection的使用
Collectionx.java的源文件如下:
import java.util.*;
public class Collectionx{
public static Collection fill(Collection c,int start,int size){
for(int i=start;i<start+size;i++)
c.add(Integer.toString(i));
return c;
}
public static Collection fill(Collection c,int size){
return fill(c,0,size);
}
public static Collection fill(Collection c){
return fill(c,0,10);
}
public static Collection newCollection(){
return fill(new ArrayList());
}
public static Collection newCollection(int start,int size){
return fill(new ArrayList(),Stary,size);
}
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-24 17:09

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表