集合类的优点:
任何集合类都可以动态地改变自身的大小。
集合类的缺点:
类型未知。将对象置入集合时会丢失对象的类型信息。因为为了成为“常规”工具,对象实际容纳的是“Object"句柄。应该知道”Object"包括所有对象,因为所有类都是从Object类继承而来。但不包括基本数据类型。
由于类型丢失问题,从集合内取得一个对象,在正式使用它之前一定要进行造型(具体说来是下溯造型)。
类型丢失意味着我们可以将任何类型的对象放入一个集合中,但Java为了防止滥用集合中的对象,进行了“违例”控制,例如下述代码:
class Cat{ //猫类
private int num;
public cat(int i){ num = i;}
}
class Dog{ //狗类
private int num;
public Dog(int i){ num = i;}
}
public class CatAndDog{ //猫狗类
public static void main(String[] args){
Vector cats = new Vector(); //创建猫类矢量
for(int i = 0;i < 5; i++)
cats.addElement(new Cat(i));
cats.addElement(new Dog(5)); //狗类也可以存入,不会报错
for(int j = 0;j < 6; j++)
(Cat)cats.elementAt(i); //运行期进行下溯造型时出现违例
}
}
记住String类例外,因为如果目标类型不是String类型,编译器会自动调用对象的toString()方法。
上面的代码是在运行期检查类型问题,当然,可以实现编译时的类型检测,这需要调整代码结构:
public class CatAndDog{
Vector v = new Vector((); //利用组合
public void addElement(Cat cat){ //使得只能添加Cat类
v.addElement(cat);
}
public Cat elementAt(int index){
return (Cat)v.elementAt(index);
}
//...
}
上述代码利用组合(继承会有点麻烦),将矢量操作放进新类方法中,使用方法参数限制操作类型。这样做显得有点繁琐但可以在编译期发现问题。
枚举器(Enumeration)
枚举器属于反复器(Iterator)的一种简单实现(Java1.2版本实现了反复器)。它可以是一个对象,作用是遍历一系列对象,并选择 那个序列中的每个对象,同时不让客户程序员知道或关注那个序列的基础结构。此外,我们通常认为反复器 是一种“轻量级”对象;也就是说,创建它只需付出极少的代价。
Java 的Enumeration工作原理:
class PrintData {
static void print(Enumeration e) { //接收一个枚举器
while(e.hasMoreElements())
System.out.println( e.nextElement().toString()); //打印枚举器的内容
}
}
class Enumerators2 {
public static void main(String[] args) {
Vector v = new Vector(); //创建矢量
for(int i = 0; i < 5; i++)
v.addElement(new Mouse(i));
Hashtable h = new Hashtable(); //创建散列表
for(int i = 0; i < 5; i++)
h.put(new Integer(i), new Hamster(i));
System.out.println("Vector");
PrintData.print(v.elements()); //打印矢量
System.out.println("Hashtable");
PrintData.print(h.elements()); //打印散列表
}
}
仔细分析上述代码:集合类可以通过elements()方法生成一个枚举对象;枚举器不关心集合的特定类型,它只是使用hasMoreElements()和nextElement()进行访问遍历。
Vector:
Vector的用法很简单,这已在前面的例子中得到了证明。尽管我们大多数时候只需用addElement()插入对 象,用 elementAt()一次提取一个对象,并用elements()获得对序列的一个“枚举”,但它还有一些其他方法很有用处,可以查看相关文档。
BitSet:
BitSet实际是由“二进制位”构成的一个 Vector。如果希望高效率地保存大量“开-关”信息,就应使用 BitSet。它只有从尺寸的角度看才有意义;如果希望的高效率的访问,那么它的速度会比使用一些固有类型 的数组慢一些。 此外,BitSet的最小长度是一个长整数(Long)的长度:64 位。这意味着假如我们准备保存比这更小的数据,如 8 位数据,那么 BitSet就显得浪费了。所以最好创建自己的类,用它容纳自己的标志位。
Stack:
Stack 有时也可以称为“后入先出”(LIFO)集合。换言之,我们在堆栈里最后“压入”的东西将是以后第 一个“弹出”的。和其他所有 Java 集合一样,我们压入和弹出的都是“对象”,所以必须对自己弹出的东西 进行“造型”。
Stack对象使用push()压栈,使用pop()出栈。要声明的一点是, Vector操作亦可针对 Stack 对象进行。这可能是由继承的特质决定的——Stack“属于”一种 Vector。因此,能对Vector 进行的操作亦可针对Stack 进行,例如 elementAt()方法。
Hashtable:
Vector允许我们用一个数字从一系列对象中作出选择,所以它实际是将数字同对象关联起来了。但假如我们 想根据其他标准选择一系列对象呢? 这种“从一系列对象中选择”的概念亦可叫作一个“映射”、“字典”或者“关联数组”。从概念上讲,它 看起来象一个Vector,但却不是通过数字来查找对象,而是用另一个对象来查找它们! 在Java 中,这个概念具体反映到抽象类 Dictionary身上。该类的接口是非常直观的。
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());
Groundhog2 gh = new Groundhog2(3);
if(ht.containsKey(gh))
System.out.println((Prediction)ht.get(gh));
}
}
下一篇:Java--集合类之Collection与Map