- 对象的集合:
- 数组:
- 数组若越界,则会抛出RunTimeException异常。
- Arrays用于数组,由于Java不支持模板,所以我们需要对其进行类型检查。典型的应用如下:
Arrays.fill(a1,true);
System.out.println("a1="+Arrays.asList(a1));
若我们想要对类型敏感,我们可以采用Composition的模式,产生自己的容器。 - 当我们需要复制一个数组的时候,我们可以使用System.arraycopy的static方法:
int[] i=new int[7];
int[] k=new int[5];
Arrays.fill(k,103);
System.arraycopy(i,0,k,0,k.length); - 数组的比较:使用Arrays.equals来对数组进行比较;但是因为没有了泛型算法,所以当我们要提供自有的比较方法的时候,我们应该实现java.lang.Comparable接口,如下:
public class CompType implements Comparable {
int i;
int j;
public CompType(int n1,int n2) {
i=n1;
j=n2;
}
public int compareTo(Object rv) {
return (i<rv?-1:(i==rv?0:1));
}
private static Random r=new Random();
public static Generator generator() {
return new Generator() {
public Object next() {
return new CompType(r.nextInt(100),r.nextInt(100));
}
};
}
public static void main(String[] args) {
CompType[] a=new CompType[10];
Arrays2.fill(a,generator());
Arrays.sort(a);
}
}
这 里我们只用到了i的值。若我们没有提供compareTo方法,那么当调用到sort方法时,就回抛出ClassCastException异常。若我们 想要逆序排序,我们可以通过设置sort的第二个参数为Collections.reverseOrder方法。同样我们可以象C++一样提供一个 Comparator接口,来提供比较的方法:
class CompTypeComparator implements Comparator {
public int compare(Object v1,Object v2) {
int j1=((CompType)v1).j;
int j2=((CompType)v2).j;
return (j1<j2?-1:(j1==j2?0:1));
}
}
然后设置sort的第二个参数为new CompTypeComparator() - 一旦数组排序好后,我们可以使用Arrays.binarySearch来进行快速查询。
- 迭代器:
- 用iterator()方法传递一个Iterator对象,第一次调用next()方法时,会传给序列中的第一个元素。
- next()方法返回下一个元素。
- hasNext()方法查询是否还有其他元素。
- remove()方法删除迭代器最后一个元素。
- List:通常用add方法加对象,用get方法取对象,用iterator方法获取迭代器。
- List:最重要的特征是有序,它在Collections基础上添加了大量的方法。它可以产生ListIterator对象,用它除了可以在中间插入和删除对象外,还可以沿两个方向遍历List。
- ArrayList:用数组实现,能快速访问,但在中间插入和删除对象效率较低,ListIterator只能用于反向遍历ArrayList的场合,不要用于插入和删除对象。
- LinkedList:对顺序访问进行优化,在中间插入和删除对象效率最高,但随机访问较慢,此外还有addFirst、addLast、getFirst、getLast、removeFirst和removeLast等方法,可以把它当作栈,队列和双向队列来使用。
- Set:
- Set:加入Set的元素必须唯一,这和C++ STL中是一样的,要想加入Set,元素必须实现equals,这样才能表明唯一性。它的接口和Collection的一样,不保证会采用什么顺序存储元素。
- HashSet:为优化查询速度而设计的Set,元素还要额外定义hashCode方法。
- TreeSet:有序的Set,其底层是一棵树。这样就可以从Set里面提取一个有序序列。
- LinkedHashSet:在内部使用链表的Set,既有HashSet的查询速度,又能保存元素被加进去的顺序。用Iterator迭代器遍历Set的时候,保持插入时的顺序。
- SortedSet:里面的元素一定是有序的,comparator()方法返回所用的Comparator对象,或者用null表示 它使用Object自有的排序方法;first()返回最小的元素;last()返回最大的元素;subSet(fromElement, toElement)返回Set的子集;headSet(toElement)返回子集,其中的元素都小于toElement;tailSet (fromElement)返回子集,其中的元素都大于fromElement。
- Map:put(key,value)方法放入一个值,并且与key关联起来;get(key)会返回该值;containsKey()和containsValue()测试该Map是否含有某个键或值。
- Map:维持键—值的关系。
- HashMap:基于Hash的实现,提供恒定时间的查询和插入。在构造函数中可以设置Hash表的capacity和load factor,通过构造函数来调节性能。
- LinkedHashMap:类似于HashMap,但因为内部采用链表的形式,所以用Iterator遍历的时候,会按插入的顺序或最先使用的顺序进行访问。除了用Iterator外,其它情况比HashMap稍慢。
- TreeMap:基于红黑树数据结构的实现,它是按顺序(根据Comparable或者Comparator)排列的,它的特点是有序,并且唯一实现了subMap方法,该方法能获取树的一部分。
- WeakHashMap:一个weak key的Map,为某些特殊问题设计,它能让Map释放所持有的对象。若某个对象只在Map当中充当键,那它将被回收。
- IdentityHashMap:用==替代equals,用于解决特殊问题。
- SortedMap,只有TreeMap这一实现,它的键肯定是有序的,comparator()返回所用的Comparator对 象,null代表自有的比较方法;firstKey()返回第一个键;lastKey()返回最后一个键;subMap(fromKey,toKey)返 回一个子集,包括前者,不包括后者;headMap(toKey)返回一个子集,其键小于toKey;tailMap(fromKey)返回一个子集,其 键均大于fromKey;
- Collections含有的工具:相当于STL中的算法。
- [max/min](Collection):用自然对象内置的算法进行比较,返回最大和最小的元素。
- [max/min](Collection,Comparator):用Comparator对象进行比较,返回最大和最小的元素。
- [indexOfSubList/lastIndexOfSubList](List source,List target):获取target第一次和最后一次出现在source中的位置。
- replaceAll(List list,Object oldVal,Object newVal):将所有的oldVal替换成newVal。
- reverse():颠倒List的顺序。
- rotate(List list,int distance):把所有的元素循环向后移动distance位。
- copy(List dest,List src):将src的元素拷贝到dest。
- swap(List list,int i,int j):互换i和j位置上的元素。
- fill(List list,Object o):把list里面的全部元素替换成o。
- nCopies(int n,Object o):返回一个有n个元素的不可变的List,而且这个List中的所有元素全都指向o。
- enumeration(Collection):返回一个老式的Enumeration。
- list(Enumeration e):用这个Enumeration生成一个ArrayList,并且返回这个ArrayList。
- 可以用Arrays.asList把数组改造成List。
- BitSet:同STL一样,我们可以使用BitSet来存储"是非"信息。
- 数组:
- I/O类:
- File类:用于处理文件和目录的类
- 目录列表器:通过不带参数的list方法,来返回String数组;或者通过传递一个实现了FilenameFilter接口的对象来过滤。举例:
import java.io.*;
import java.util.*;
import java.util.regex.*;
import com.bruceeckel.util.*;
public class DirList {
public static void main(String[] args) {
File path = new File(".");
String[] list;
if(args.length == 0)
list = path.list();
else
list = path.list(new DirFilter(args[0]));
Arrays.sort(list, new AlphabeticComparator());
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
}
class DirFilter implements FilenameFilter {
private Pattern pattern;
public DirFilter(String regex) {
pattern = Pattern.compile(regex);
}
public boolean accept(File dir, String name) {
return pattern.matcher(
new File(name).getName()).matches();
}
}
当然我们也可以通过匿名类的方法,减少无关的类的使用。 - 查看与创建目录:getAbsolutePath方法获取绝对路径;还有canRead、canWrite、getName、 getParent、getPath、length、lastModified、isFile、isDirectory等方法。renameTo、 delete、mkdirs方法来重命名、删除和创建。
- 目录列表器:通过不带参数的list方法,来返回String数组;或者通过传递一个实现了FilenameFilter接口的对象来过滤。举例:
- 输入与输出:I/O类库常使用“流”这种抽象。
- InputStream:代表那些能从各种输入源获取数据的类,这些源包括byte数组、String对象、文件、管道、流序列、其他源(例如: Internet)这些源都有与之对应的子类。ByteArrayInputStream、StringBufferInputStream、 FileInputStream、PipedInputStream、SequenceInputStream、FilterInputStream。其 中FilterInputStream又包含有:DataInputStream、BufferedInputStream、 LineNumberInputStream、PushbackInputStream。
- OutputStream:ByteArrayOutputStream、FileOutputStream、 PipedOutputStream、FilterOutputStream。其中FilterOutputStream又包含有: DataOutputStream、PrintStream、BufferedOutputStream。
- Reader和Writer:主要是针对国际化问题,这样I/O就能支持Unicode了。
- 常见的I/O流的使用方法,举例:
import com.bruceeckel.simpletest.*;
import java.io.*;
public class IOStreamDemo {
private static Test monitor = new Test();
// Throw exceptions to console:
public static void main(String[] args)
throws IOException {
// 1. Reading input by lines:
BufferedReader in = new BufferedReader(
new FileReader("IOStreamDemo.java"));
String s, s2 = new String();
while((s = in.readLine())!= null)
s2 += s + "/n";
in.close();
// 1b. Reading standard input:
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
System.out.print("Enter a line:");
System.out.println(stdin.readLine());
// 2. Input from memory
StringReader in2 = new StringReader(s2);
int c;
while((c = in2.read()) != -1)
System.out.print((char)c);
// 3. Formatted memory input
try {
DataInputStream in3 = new DataInputStream(
new ByteArrayInputStream(s2.getBytes()));
while(true)
System.out.print((char)in3.readByte());
} catch(EOFException e) {
System.err.println("End of stream");
}
// 4. File output
try {
BufferedReader in4 = new BufferedReader(
new StringReader(s2));
PrintWriter out1 = new PrintWriter(
new BufferedWriter(new FileWriter("IODemo.out")));
int lineCount = 1;
while((s = in4.readLine()) != null )
out1.println(lineCount++ + ": " + s);
out1.close();
} catch(EOFException e) {
System.err.println("End of stream");
}
// 5. Storing & recovering data
try {
DataOutputStream out2 = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out2.writeDouble(3.14159);
out2.writeUTF("That was pi");
out2.writeDouble(1.41413);
out2.writeUTF("Square root of 2");
out2.close();
DataInputStream in5 = new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
// Must use DataInputStream for data:
System.out.println(in5.readDouble());
// Only readUTF() will recover the
// Java-UTF String properly:
System.out.println(in5.readUTF());
// Read the following double and String:
System.out.println(in5.readDouble());
System.out.println(in5.readUTF());
} catch(EOFException e) {
throw new RuntimeException(e);
}
// 6. Reading/writing random access files
RandomAccessFile rf =
new RandomAccessFile("rtest.dat", "rw");
for(int i = 0; i < 10; i++)
rf.writeDouble(i*1.414);
rf.close();
rf = new RandomAccessFile("rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
rf = new RandomAccessFile("rtest.dat", "r");
for(int i = 0; i < 10; i++)
System.out.println("Value " + i + ": " +
rf.readDouble());
rf.close();
monitor.expect("IOStreamDemo.out");
}
} - 标准I/O:来自于Unix的概念,例如:键盘和屏幕。
- 读取标准输入:System.in、System.out、System.err
- 标准I/O的重定向:System类提供几个重定向的方法,setIn(InputStream)、setOut(PrintStream)、setErr(PrintStream)。
- New I/O:为了提高速度,Java 1.4引入了nio。
- ByteBuffer:存储byte数据的Buffer,并且是唯一能直接同channel打交道的buffer。
- MappedByteBuffer:内存映射文件,可以把它当作全部读进内存,然后当成数组来访问。
- 文件锁:允许以文件为共享资源,对访问进行同步化处理。要获取整个文件的锁,可以用FileChannel的tryLock或lock 方法,最后用FileLock.release()释放锁。还可以通过tryLock(long position,long size,boolean shared)来锁住文件的。
- 压缩:Java I/O还提供能读写。它提供CheckedInputStream、CheckedOutputStream用于返回checksum, DeflaterOutputStream是压缩类的基类,ZipOutputStream把数据压缩成Zip文件,GZIPOutputStream把 数据压缩成GZip文件,InflaterInputStream是解压缩类的基类,有ZipInputStream和GZIPInputStream两 个子类。举例:
- GZip:
import com.bruceeckel.simpletest.*;
import java.io.*;
import java.util.zip.*;
public class GZIPcompress {
private static Test monitor = new Test();
// Throw exceptions to console:
public static void main(String[] args)
throws IOException {
if(args.length == 0) {
System.out.println(
"Usage: /nGZIPcompress file/n" +
"/tUses GZIP compression to compress " +
"the file to test.gz");
System.exit(1);
}
BufferedReader in = new BufferedReader(
new FileReader(args[0]));
BufferedOutputStream out = new BufferedOutputStream(
new GZIPOutputStream(
new FileOutputStream("test.gz")));
System.out.println("Writing file");
int c;
while((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
System.out.println("Reading file");
BufferedReader in2 = new BufferedReader(
new InputStreamReader(new GZIPInputStream(
new FileInputStream("test.gz"))));
String s;
while((s = in2.readLine()) != null)
System.out.println(s);
monitor.expect(new String[] {
"Writing file",
"Reading file"
}, args[0]);
}
} - Zip:
import com.bruceeckel.simpletest.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class ZipCompress {
private static Test monitor = new Test();
// Throw exceptions to console:
public static void main(String[] args)
throws IOException {
FileOutputStream f = new FileOutputStream("test.zip");
CheckedOutputStream csum =
new CheckedOutputStream(f, new Adler32());
ZipOutputStream zos = new ZipOutputStream(csum);
BufferedOutputStream out =
new BufferedOutputStream(zos);
zos.setComment("A test of Java Zipping");
// No corresponding getComment(), though.
for(int i = 0; i < args.length; i++) {
System.out.println("Writing file " + args[i]);
BufferedReader in =
new BufferedReader(new FileReader(args[i]));
zos.putNextEntry(new ZipEntry(args[i]));
int c;
while((c = in.read()) != -1)
out.write(c);
in.close();
}
out.close();
// Checksum valid only after the file has been closed!
System.out.println("Checksum: " +
csum.getChecksum().getValue());
// Now extract the files:
System.out.println("Reading file");
FileInputStream fi = new FileInputStream("test.zip");
CheckedInputStream csumi =
new CheckedInputStream(fi, new Adler32());
ZipInputStream in2 = new ZipInputStream(csumi);
BufferedInputStream bis = new BufferedInputStream(in2);
ZipEntry ze;
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze);
int x;
while((x = bis.read()) != -1)
System.out.write(x);
}
if(args.length == 1)
monitor.expect(new String[] {
"Writing file " + args[0],
"%% Checksum: //d+",
"Reading file",
"Reading file " + args[0]}, args[0]);
System.out.println("Checksum: " +
csumi.getChecksum().getValue());
bis.close();
// Alternative way to open and read zip files:
ZipFile zf = new ZipFile("test.zip");
Enumeration e = zf.entries();
while(e.hasMoreElements()) {
ZipEntry ze2 = (ZipEntry)e.nextElement();
System.out.println("File: " + ze2);
// ... and extract the data as before
}
if(args.length == 1)
monitor.expect(new String[] {
"%% Checksum: //d+",
"File: " + args[0]
});
}
} - 对象序列化:能将一个实现了Serializable接口的对象转换成一组byte,这样日后要使用这个对象可以直接从byte数据恢 复出来;我们可以让对象去实现Externalizable来控制序列化的过程(创建新的子对象)。同时在序列化和恢复的时候会调用 writeExternal和readExternal方法。若我们在一个对象中不希望某个变量被序列化,我们应该使用transient关键字。
- GZip:
- File类:用于处理文件和目录的类