丢了也不怕!如何让移动设备守口如瓶
一、用数组来持有对象
数组与其它容器的区别体现在三个方面,效率,类型识别和可以持有primitives,数组是java提供的,能随机存储和访问reference序列的诸多方法中,最有效率的一种。数组的缺点就是:当你创建一个数组的时候,它的容量就确定了,而且在其生命周期不会改变。数组的类型识别,当数组在创建的时候,你就已经知道了(定义了)它所持有的对象是什么类型的,也就是说它会在编译的时候做类型检查,从而防止你插入错误类型的对象或者在提取对象的时候把类型搞错了,这也引出了数组的第三个特点,它可以持有primitives变量,而容器类却不可以。
数组是一流的对象,不管你用的是那一种类型的数组,数组的标识符实际上都是一个“创建在堆中(heap)的实实在在对象”的reference。
注:对象数组持有的是reference,而primitive类型数组则直接持有值。
Java.util这个包中的Arrays类,它包括了一组可用于数组的static方法,其中有四个基本方法:用来比较两个数组是否相等的equals(),用于填充数组的fill(),用于对于数组排序sort(),以及用于在一个已排序的数组查找元素的binarySearch(),所有这些方法都对primitives和Object进行了重载。此外还有一个asList()方法,它接受一个数组,返回的是一个List容器。当你要复制整个数组的时候,java的类库里还提供了一个System.arraycopy()的static方法,相比for循环,这个速度比较快,传给arraycopy()的参数有:源数组,标识从源数组那个位置开始拷贝的偏移量,目标数组,标识从目标数组那个位置开始拷贝的偏移量,以及要拷贝的元素的数量。
注:对象数组和primitive数组都能拷贝,如果你拷贝的是对象数组,那么你只拷贝了他们的reference,对象本身不会被拷贝,这被称为"浅拷贝".
为了比较两个数组是否相等,Arrays还提供了经过重载的equals()方法,来成对各种primitive和Object做相等的判断。两个数组要想完全相等,它们必须要相等的元素数量,并且每个位置上的元素必须和另一个数组相同位置上的元素相等。元素的相等性会用equals()判断。
数组的排序,对于对象数组的排序,Java里有两种能让你实现比较功能的方法,一种是实现java.lang.Comparable接口,并以此实现类“自有的”比较方法。这是一个很简单的接口,它只有一个compareTo()方法,这个方法能接受另一个对象作为参数,如果现有对象比参数小,会返回负数,相等返回零,大则返回正数。另一种通过现实Comparator接口,这个接口有两种方法,compare()和equals()方法,其中compare()这个方法时必须要求overload的。总之不论是primitive还是对象数组,只要它实现了comparable接口或是有一个与之相关Comparator对象(这个对象现实了Comparator的接口),我们就可以对数组排序了。
查询一个有序数组可以使用Arrays.binarySearch()进行快速查询,如果Arrays.binarySearch()找到了,它会返回一个大于或等于零的值,否则会返回一个 -(插入点)-1,这个插入点就是在所有比要找的那个值更大的值中的最小值的下标.如果所有的值都比要找的值小,那么插入点的值就是数组的大小。
注:如果在排序的时候使用了Comparator,在进行Arrays.binarySearch()也需要将这个Comparator作为参数传过去。
总而言之,你要持有一组对象,首先得应该就是数组,接下来我们要讲更为一般的情况,也就是写程序的时候不知道到底要用多少对象,或者要用更为复杂的方式来存储对象。
Java还提供了“容器类”,其基本的类型有List,Set和Map。Java要解决“怎样持有对象“,它把这个问题分成两类:
1、Collection:通常是一组有一定规律的独立的元素。List必须按照特定的顺序持有元素,Set则不能保存重复的元素。Collection只允许每个位置存放一个对象。
2、Map:一组以“键-值”(key-value)形式出现的pair,Map可以返回键(key)的Set,值的Collection或者pair的Set,Map不接受重复的pair,至于是不是重复,要看key的值是不是相同。
容器类的缺点就是你在向容器里放入对象的时候,会把对象类型的信息给弄丢了,这是因为开发容器类的程序员不知道你要用它来存放什么类型的对象,而让容器类仅保存特定类型的对象又会影响其通用性。所以容器被做成了持有Object对象类型,也就是所有对象根类的reference,这样它就可以持有任意类型的对象了。
由于你已经知道容器持有那个对象(Object)的reference,当你要使用容器里的对象的reference的时候,就需要进行类型转换,否则你就只能使用Object根类的方法,而这似乎没有什么意义。值得庆幸的是,Java不会让你误用容器里的对象的。假设你往容器里放了一个A和一个B,当你将B的reference拿出来当A来使用的时候,就会引发一个RuntimeException。
二、迭代器
无论哪种容器,都得有方法将对象放进去,也能将对象取出来。容器的任务就是存放对象。“迭代器”是一种对象,它的任务就是,能在让“程序员不知道或者不关心他所处理的是什么样的底层序列结构”的情况下,就能在序列中前后移动,并选取其中的对象。Java的迭代器是受限制的,它所能做的事情包括:
1.用Iterator()方法让容器传给你一个Iterator对象。
2.用next()方法获取序列中下一个对象。注:第一次调用Iterator的next()方法时返回的是序列中第一个对象 。
3.用hasNext()方法查询序列中时候是否还有其他对象。
4.用remove()方法删除迭代器返回的最后一个元素。
就这些了,需要注意的是对于List,还有一个更为精巧的Listiterator(),Iterator()采用的“全部拿走容器里的所有对象,然后在一个一个的处理”的思路,这使得Iterator()的作用非常强大。例如下面这个通用的打印程序。
![]()
Import java.util.*;
public class Printer{
static void printAll(Iterator e){
while(e.hasnext()){
//分别调用容器队象的toString()方法。
System.out.println((String)e.next());
}
}
}
