俗话说得好:天有不测风云。我们就是 云中的雨滴,不知道要落在什么地方。
现在的情形不太好写Blog了,但是我仍然在学习。
今天说说对象的容纳吧。
我们需要容纳对象的容器在于:我们的程序中不知道会出现多少对象,也不知道他们的类型。于是我们用容器(也可以叫集合吧)把他们“装”起来。当然他们是无限大,可以这么想象。值得注意的是想int这样的基本类型是不可以放入这些集合中的。
java 类库中为我们提供的是一系列的容器,我们可以根据需求选择我们需要的,适合我们的用。
常见的如 ArrayList,Hashtable,Map ,Set….等
由于这些容器封装了我们得数据,我们使用得时候也必须使用他得方法。例如从一个集合中得到数据或是写入数据 ,不过我们不用担心,这些方法大都是一样的。这里写个例子:
Collection c = new ArrayList();
Iterator iter = c.iterator();
while(iter.hasNext()){
ArrayList a = (ArrayList)iter.next();
}
这里还有一个更早的东西Enumeration。他是一个和Iterator差不多的反复起(迭代器), Vector ,Stack,Map等集合与新的集合库有不同的操作方法,他们使用Enumeration。例如
Vector v = new Vector();
…//do something
Enumeration e = v.elements() ;
while(e.hasMoreElements){
Vector a = (Vector)e.nextElement();
}
Enumeration 比起Iterator来他的指针是单向的,而且Iterator的方法名字也较Enumeration更简短。
当然我们并不只是可以选择这两样,Iterator下面还有一些如listIterator等。。。
从集合中取对象是要小心的,因为我们根本不知道她里面到底放的是什么东西。所以我们在得到我们的东西之前应该“造型”如上面的例子。这也常常隐含了错误,比如不小心把不合适的类也放进去了,而出来的时候就得到了一个不知道的东西。
我们怎样选择集合呢?
这是我们最关心的问题,然而每一种集合都有他的特性,现在的问题变成我们需要什么 ?选择一个集合并不太困难,因为他们的差别不是很大,而我们了解的也不需要太多。例如我们应该知道ArrayList和LinkedList的区别。在需要大量的插入和删除操作的时候我们应该选择LinkedList,否则还是ArrayList比较好。当我们需要一个没有重复对象数据的集合的时候,我们可以选择Set,是HashSett还是ArraySet呢?作者通过试验告诉我们HashSet比ArraySet要好得多。Map是一个用作“映射”或“字典”的时候使用的。你可以考虑一下测试一下他么之间的新能,HashMap,TreeMap还是ArrayMap。不过暂时不要使用ArrayMap,应为他的性能不知是否改善。在此之前你用TreeMap就行了。
注意的
1,一些未支持的操作
例子: 静态方法Arrays.toList()能将一个数组转化成List,但是如此得到的List是否能得到一般的方法呢?
书上的程序://: Unsupported.java
// Sometimes methods defined in the Collection
// interfaces don’t work!
package c08.newcollections;
import java.util.*;
public class Unsupported {
private static String[] s = {
"one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten",
};
static List a = Arrays.toList(s);
static List a2 = Arrays.toList(
new String[] { s[3], s[4], s[5] });
public static void main(String[] args) {
Collection1.print(a); // Iteration
System.out.println(
"a.contains(" + s[0] + ") = " +
a.contains(s[0]));
System.out.println(
"a.containsAll(a2) = " +
a.containsAll(a2));
System.out.println("a.isEmpty() = " +
a.isEmpty());
System.out.println(
"a.indexOf(" + s[5] + ") = " +
a.indexOf(s[5]));
// Traverse backwards:
ListIterator lit = a.listIterator(a.size());
while(lit.hasPrevious())
System.out.print(lit.previous());
System.out.println();
// Set the elements to different values:
for(int i = 0; i < a.size(); i++)
a.set(i, "47");
Collection1.print(a);
// Compiles, but won’t run:
lit.add("X"); // Unsupported operation
a.clear(); // Unsupported
a.add("eleven"); // Unsupported
a.addAll(a2); // Unsupported
a.retainAll(a2); // Unsupported
a.remove(s[0]); // Unsupported
a.removeAll(a2); // Unsupported
}
} ///:~
这样就导致了UnsupportedOperationException(操作未支持违例),这种设计主要为了新的集合可以不需要为集合接口的所有方法提供有意义的定义,同时他也只在实现的时候出现,而不是使用的时候。
对于集合中的一系列对象,我们关心的还有他们的排序和查找问题。当然这写也是应该具有的基本功能。
Arrays类为所有基本数据类型的数组提供了一个过载的sort()和binaraySearch(),也可用于String和Object
使用方法;Arrays.sort();
Arrays.binarySearch();
注意的是我们必须想执行Arrays.sort();然后才执行Arrays.binarySearch(),否则会出现预料不到的错误,如死循环。还有sort的排序是以字典顺序,也就是大写字符集载小写字符集前面。
如果想改变排序方式,我们可以创建一个对象实现Comparator接口,过载compare()方法。然后把这个对象传给sort,当然在binarySearch中使用的参数也应该是实现Comparator这个接口的同一个对象。
书上例子:
//: AlphaComp.java
// Using Comparator to perform an alphabetic sort
package c08.newcollections;
import java.util.*;
public class AlphaComp implements Comparator {
public int compare(Object o1, Object o2) {
// Assume it’s used only for Strings…
String s1 = ((String)o1).toLowerCase();
String s2 = ((String)o2).toLowerCase();
return s1.compareTo(s2);
}
public static void main(String[] args) {
String[] s = Array1.randStrings(4, 10);
Array1.print(s);
AlphaComp ac = new AlphaComp();
Arrays.sort(s, ac);
Array1.print(s);
// Must use the Comparator to search, also:
int loc = Arrays.binarySearch(s, s[3], ac);
System.out.println("Location of " + s[3] +
" = " + loc);
}
}
如果要排序查询的对象本身实现了Compoarator 接口并写了compareTo(大于返回1,小于-1,等于0),那么也可以直接使用Arrays.sort()。
例如:
//: CompClass.java
// A class that implements Comparable
package c08.newcollections;
import java.util.*;
public class CompClass implements Comparable {
private int i;
public CompClass(int ii) { i = ii; }
public int compareTo(Object o) {
// Implicitly tests for correct type:
int argi = ((CompClass)o).i;
if(i == argi) return 0;
if(i < argi) return -1;
return 1;
}
public static void print(Object[] a) {
for(int i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
System.out.println();
}
public String toString() { return i + ""; }
public static void main(String[] args) {
CompClass[] a = new CompClass[20];
for(int i = 0; i < a.length; i++)
a[i] = new CompClass(
(int)(Math.random() *100));
print(a);
Arrays.sort(a);
print(a);
int loc = Arrays.binarySearch(a, a[3]);
System.out.println("Location of " + a[3] +
" = " + loc);
}
} ///:~
其他的和Arrays都一样。
现面说说怎样创建同步的Colloction或是Map。
例:
//: Synchronization.java
// Using the Collections.synchronized methods
package c08.newcollections;
import java.util.*;
public class Synchronization {
public static void main(String[] args) {
Collection c =
Collections.synchronizedCollection(
new ArrayList());
List list = Collections.synchronizedList(
new ArrayList());
Set s = Collections.synchronizedSet(
new HashSet());
Map m = Collections.synchronizedMap(
new HashMap());
}
}
有些时候我们需要创建不可修改的Collection或是Map,下面的例子就是如何创建的方法:将原始容器传递进入一个方法,并令其传回一个只读版本。
//: ReadOnly.java
// Using the Collections.unmodifiable methods
package c08.newcollections;
import java.util.*;
public class ReadOnly {
public static void main(String[] args) {
Collection c = new ArrayList();
Collection1.fill(c); // Insert useful data
c = Collections.unmodifiableCollection(c);
Collection1.print(c); // Reading is OK
//! c.add("one"); // Can’t change it
List a = new ArrayList();
Collection1.fill(a);
a = Collections.unmodifiableList(a);
ListIterator lit = a.listIterator();
System.out.println(lit.next()); // Reading OK
//! lit.add("one"); // Can’t change it
Set s = new HashSet();
Collection1.fill(s);
s = Collections.unmodifiableSet(s);
Collection1.print(s); // Reading OK
//! s.add("one"); // Can’t change it
Map m = new HashMap();
Map1.fill(m, Map1.testData1);
m = Collections.unmodifiableMap(m);
Map1.print(m); // Reading OK
//! m.put("Ralph", "Howdy!");
}
}这里如果试图改变集合,那么就会出现UnsupportedOperationException违例。
我们看看书上的总结:
“下面复习一下由标准Java(1.0和1.1)库提供的集合(BitSet未包括在这里,因为它更象一种负有特殊使命的类):
(1) 数组包含了对象的数字化索引。它容纳的是一种已知类型的对象,所以在查找一个对象时,不必对结果进行造型处理。数组可以是多维的,而且能够容纳基本数据类型。但是,一旦把它创建好以后,大小便不能变化了。
(2) Vector(矢量)也包含了对象的数字索引——可将数组和Vector想象成随机访问集合。当我们加入更多的元素时,Vector能够自动改变自身的大小。但Vector只能容纳对象的句柄,所以它不可包含基本数据类型;而且将一个对象句柄从集合中取出来的时候,必须对结果进行造型处理。
(3) Hashtable(散列表)属于Dictionary(字典)的一种类型,是一种将对象(而不是数字)同其他对象关联到一起的方式。散列表也支持对对象的随机访问,事实上,它的整个设计方案都在突出访问的“高速度”。
(4) Stack(堆栈)是一种“后入先出”(LIFO)的队列。
若你曾经熟悉数据结构,可能会疑惑为何没看到一套更大的集合。从功能的角度出发,你真的需要一套更大的集合吗?对于Hashtable,可将任何东西置入其中,并以非常快的速度检索;对于Enumeration(枚举),可遍历一个序列,并对其中的每个元素都采取一个特定的操作。那是一种功能足够强劲的工具。
但Hashtable没有“顺序”的概念。Vector和数组为我们提供了一种线性顺序,但若要把一个元素插入它们任何一个的中部,一般都要付出“惨重”的代价。除此以外,队列、拆散队列、优先级队列以及树都涉及到元素的“排序”——并非仅仅将它们置入,以便以后能按线性顺序查找或移动它们。这些数据结构也非常有用,这也正是标准C++中包含了它们的原因。考虑到这个原因,只应将标准Java库的集合看作自己的一个起点。而且倘若必须使用Java 1.0或1.1,则可在需要超越它们的时候使用JGL。
如果能使用Java 1.2,那么只使用新集合即可,它一般能满足我们的所有需要。注意本书在Java 1.1身上花了大量篇幅,所以书中用到的大量集合都是只能在Java1.1中用到的那些:Vector和Hashtable。就目前来看,这是一个不得以而为之的做法。但是,这样处理亦可提供与老Java代码更出色的向后兼容能力。若要用Java1.2写新代码,新的集合往往能更好地为你服务”。
好了,今天就到这里了。