作者:Flyingis
数组是Java语言内置的类型,除此之外,Java有多种保存对象引用的方式。Java类库提供了一套相当完整的容器类,使用这些类的方法可以保存和操纵对象。下面分别进行讨论,在研究Java容器类之前,先了解一下Java数组的基本功能和特性。
1. 数组的基本特性
数组与其它种类的容器(List/Set/Map)之间的区别在于效率、确定的类型和保存基本类型数据的能力。数组是一种高效的存储和随机访问对象引用序列的方式,使用数组可以快速的访问数组中的元素。但是当创建一个数组对象(注意和对象数组的区别)后,数组的大小也就固定了,当数组空间不足的时候就再创建一个新的数组,把旧的数组中所有的引用复制到新的数组中。
Java中的数组和容器都需要进行边界检查,如果越界就会得到一个RuntimeException异常。这点和C++中有所不同,C++中vector的操作符[]不会做边界检查,这在速度上会有一定的提高,Java的数组和容器会因为时刻存在的边界检查带来一些性能上的开销。
Java中通用的容器类不会以具体的类型来处理对象,容器中的对象都是以Object类型处理的,这是Java中所有类的基类。另外,数组可以保存基本类型,而容器不能,它只能保存任意的Java对象。
一般情况下,考虑到效率与类型检查,应该尽可能考虑使用数组。如果要解决一般化的问题,数组可能会受到一些限制,这时可以使用Java提供的容器类。
2. 操作数组的实用功能
在java.util.Arrays类中,有许多static静态方法,提供了操作数组的一些基本功能:
equals()方法----用于比较两个数组是否相等,相等的条件是两个数组的元素个数必须相等,并且对应位置的元素也相等。
fill()方法----用以某个值填充整个数组,这个方法有点笨。
asList()方法----接受任意的数组为参数,将其转变为List容器。
binarySearch()方法----用于在已经排序的数组中查找元素,需要注意的是必须是已经排序过的数组。当Arrays.binarySearch()找到了查找目标时,该方法将返回一个等于或大于0的值,否则将返回一个负值,表示在该数组目前的排序状态下此目标元素所应该插入的位置。负值的计算公式是“-x-1”。x指的是第一个大于查找对象的元素在数组中的位置,如果数组中所有的元素都小于要查找的对象,则x = a.size()。如果数组中包含重复的元素,则无法保证找到的是哪一个元素,如果需要对没有重复元素的数组排序,可以使用TreeSet或者LinkedHashSet。另外,如果使用Comparator排序了某个对象数组,在使用该方法时必须提供同样的Comparator类型的参数。需要注意的是,基本类型数组无法使用Comparator进行排序。
sort()方法----对数组进行升序排序。
在Java标准类库中,另有static方法System.arraycopy()用来复制数组,它针对所有类型做了重载。
3. 数组的排序
在Java1.0和1.1两个版本中,类库缺少基本的算法操作,包括排序的操作,Java2对此进行了改善。在进行排序的操作时,需要根据对象的实际类型执行比较操作,如果为每种不同的类型各自编写一个不同的排序方法,将会使得代码很难被复用。一般的程序设计目标应是“将保持不变的事物与会发改变的事物相分离”。在这里,不变的是通用的排序算法,变化的是各种对象相互比较的方式。
Java有两种方式来实现比较的功能,一种是实现java.lang.Comparable接口,该接口只有一个compareTo()方法,并以一个Object类为参数,如果当前对象小于参数则返回负值,如果相等返回零,如果当前对象大于参数则返回正值。另一种比较方法是采用策略(strategy)设计模式,将会发生变化的代码封装在它自己的类(策略对象)中,再将策略对象交给保持不变的代码中,后者使用此策略实现它的算法。因此,可以为不同的比较方式生成不同的对象,将它们用在同样的排序程序中。在此情况下,通过定义一个实现了Comparator接口的类而创建了一个策略,这个策略类有compare()和equals()两个方法,一般情况下实现compare()方法即可。
使用上述两种方法即可对任意基本类型的数组进行排序,也可以对任意的对象数组进行排序。再提示一遍,基本类型数组无法使用Comparator进行排序。
Java标准类库中的排序算法针对排序的类型进行了优化——针对基本类型设计了“快速排序”,针对对象设计的“稳定归并排序”。一般不用担心其性能。
其它相关内容:
Java容器分析--List和Set
Java容器分析--Map