我们都知道,由于Array(数组)通常意义上讲只是一个单纯的线性序列,又基于Native,凭此它的效率历来便号称Java中最高。所以通常我们也都承认Java中效率最高的存储方式就是使用数组。但是,由于数组初始化后大小固定,索引不能超出下标,缺少灵活的扩展功能等原因,使得很多人放弃了数组的使用, 转而使用Collection,List,Map,Set等接口处理集合操作。
诚然在Java中使用集合类可以极大的简化我们的代码编写量。但是,有时明明只是缓存一些线性数据,还偏偏有人要使用HashMap保存,系统为此付出了不必要的内存损耗。如果是通常的程序还没有什么,当应用在高并发或者加载高内存消耗对象时(如Image图像)无意义的频繁使用集合类将极易引发OutOfMemoryException。
我们很清楚,以List接口实现的集合类中,ArrayList内部运算是基于Array的,所以他继承了Array的优势,非常适合索引取值和存储线性数据(Vector虽然也是基于Array的,但毁在大量的synchronized上……所以很多情况下等于废了……)。但它不适合插入数据和删除数据,因为每插入或删除一次就会产生一次大量数组内容Copy的操作。而LinkedList正好与ArrayList相反,它比较适合与插入删除操作,不适合于索引取值,因为它不可以像数组一样根据索引值直接就可以定位元素的地址,而需要从头至尾一个一个的来数位置。
其实这也是当然的,但凡接触过数据结构的都会知道,任何存储结构都是有其局限性的,没有也不可能有所有方面都完美的存储方式。我们所能做的,只是尽可能使用特定范围内最有效的解决方案,而对此什么解决方法最有效呢?
一般情况下,考虑到效率与类型检查等问题,应该尽可能使用数组,所以我个人比较推荐的方式就是根据需要基于数组定制集合类。
说到这里可能很多人以开发周期及稳定、通用性为借口而直接使用JDK或第三方集合类(或者COPY代码)。其实就我个人认为,这有些因噎废食了,确实有时存储对象比较复杂,自己的集合类性能无法保障。但在大多数项目中,这种情况并不存在,我们完全有能力根据需求构造集合以避免不必要的资源占用及进行相应优化。而某些人往往只是见Hibernate等框架返回个List便有样学样的自己也List和Map到底,干脆忘了Arrays.asList等方法是为什么而存在的。
Arrays.asList方法和Collection.toArray方法就是为了集合类和数组优势互补之用,以此成为数组和Collection等集合类间的桥梁,只要有这两种方法Array和Collection就可以相互转换。那么,我们有什么理由枉费可以利用的资源而不用呢?
事实上,我们只要基本掌握Arrays类和Reflect这两个有力的武器,操作数组处理持久对象根本就是张飞吃豆芽——小菜一碟。
下面,我抛砖引玉的写些代码举例:
TestBean.java(测试用实体类)
public class TestBean {
String name;
int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ArrayUtil.java(用于Array的增、删、改、查等操作)
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Random;
public class ArrayUtil implements Serializable {
private static final long serialVersionUID = 8057374625909011982L;
// 缓存数组对象
private Object objArray;
// 数组长度
private int size = 0;
// 缓存数组对象实体类型
private String objType;
final static private Random rand = new Random();
private static ArrayUtil instance = null;
/**
* 直接注入Collection
* @param collection
* @return
*/
public static ArrayUtil getInstance(Collection collection) {
return getInstance(collection.toArray());
}
/**
* 直接注入对象数组
* @param array
*/
public static ArrayUtil getInstance(Object array) {
if (instance == null) {
instance = new ArrayUtil(array);
}
return instance;
}
/**
* 注入类产生指定大小对象数组
* @param clazz
* @param maxSize
*/
public static ArrayUtil getInstance(Class clazz, int maxSize) {
if (instance == null) {
instance = new ArrayUtil(clazz, maxSize);
}
return instance;
}
private ArrayUtil() {
}
/**
* 注入对象数组产生指定大小对象数组
* @param clazz
* @param maxSize
*/
private ArrayUtil(Class clazz, int maxSize) {
// 转为指定大小对象数组
Object array = (Object[]) Array.newInstance(clazz, maxSize);
// 初始化
init(array);
}
/**
* 直接注入对象数组
* @param array
*/
private ArrayUtil(Object array) {
init(array);
}
private void init(Object array) {
// 检查是否数组对象
if (!(array instanceof Object[])) {
throw new IndexOutOfBoundsException("Not object arrays!");
}
// 缓存数组对象
objArray = array;
// 缓存实体类型
objType = array.getClass().getComponentType().getSimpleName();
// 缓存数组长度
size = Array.getLength(objArray);
}
/**
* 返回指定对象索引位置
* @param obj
* @return
*/
public int get(Object obj) {
// 检查是否合法对象
checkObject(obj);
Object[] object = (Object[]) objArray;
for (int i = 0; i < size; i++)
if (object[i] == obj) {
return i;
}
return -1;
}
/**
* 返回指定索引位置对象
* @param index
* @return
*/
public Object get(int index) {
checkIndex(index);
return getObjectArray()[index];
}
/**
* 加载对象在指定位置
* @param obj
* @param index
*/
public void add(Object obj, int index) {
// 检查索引是否越界
checkIndex(index);
// 检查是否合法对象
checkObject(obj);
Object[] objTemp = (Object[]) objArray;
objTemp[index] = obj;
// copy临时数组到objArray
System.arraycopy(objTemp, 0, objArray, 0, objTemp.length);
}
/**
* 加载对象
* @param obj
*/
public void add(Object obj) {
// 类型检查
checkObject(obj);
// 累加
next();
// 临时缓存旧数组数组
Object[] objTemp = new Object[size];
// 加载对象
objTemp[size - 1] = obj;
// copy
System.arraycopy(objArray, 0, objTemp, 0, Array.getLength(objArray));
// 转换
objArray = objTemp;
}
/**
* 删除指定索引位置数组数据
* @param index
* @return
*/
public Object remove(int index) {
// 检查索引是否越界
checkIndex(index);
Object[] objTemp = (Object[]) objArray;
// 重新构建objArray
int j;
if ((j = size - index - 1) > 0) {
System.arraycopy(objTemp, index + 1, objTemp, index, j);
}
// 减少size
back();
return objTemp[index];
}
public boolean contains(Object obj) {
Object[] objTemp = (Object[]) objArray;
for (int i = 0; i < size; i++) {
if (hash(objTemp[i]) == hash(obj)) {
return true;
}
}
return false;
}
public Object[] sub(int startIndex,int endIndex) {
//验证索引范围
checkIndex(startIndex);
checkIndex(endIndex);
int over=endIndex-startIndex;
if(over<0)...{
throw new IndexOutOfBoundsException("Index beyond the end of the border!");
}
Object[] objTemp = (Object[]) objArray;
Object[] objs = (Object[]) Array.newInstance(objArray.getClass().getComponentType(),
over);
for(int i=startIndex;i<endIndex;i++) {
objs[i-1]=objTemp[i-1];
}
return objs;
}
public void clear() {
Object[] objTemp = (Object[]) objArray;
// 清空数据
for (int i = 0; i < size; i++) {
objTemp[i] = null;
size = 0;
}
}
/**
* 删除指定的对象实体
* @param obj
* @return
*/
public boolean remove(Object obj) {
// 检查是否合法对象
checkObject(obj);
Object[] object = (Object[]) objArray;
for (int i = 0; i < size; i++)
if (object[i] == obj) {
remove(i);
return true;
}
return false;
}
/**
* 混淆数组元素
* @return
*/
public void mixElements() {
mixElements(objArray);
}
/**
* 检查数组内元素是否为空
* @return
*/
public boolean isEmpty() {
return (size == 0);
}
/**
* 转为list
* @return
*/
public List getList() {
return Arrays.asList((Object[]) objArray);
}
/**
* 减少size
*/
private void back() {
size--;
}
/**
* 增加size
*/
private void next() {
size++;
}
/**
* 检查索引是否溢出
* @param index
*/
private void checkIndex(int index) {
if (index >= size || index < 0) {
throw new IndexOutOfBoundsException("Index " + index + " out of bounds!");
}
}
/**
* 检查对象类型
* @param obj
*/
private void checkObject(Object obj) {
if (obj instanceof Object[]) {
throw new IndexOutOfBoundsException("Not loading arrays!");
}
String type;
if (!objType.equals(type = obj.getClass().getSimpleName())) {
throw new IndexOutOfBoundsException("Not this " + type
+ " type of loading!");
}
}
/**
* 扩充数组对象
* @param obj
* @param i
* @param flag
* @return
*/
static public Object expand(Object obj, int i, boolean flag) {
int j = Array.getLength(obj);
Object obj1 = Array.newInstance(obj.getClass().getComponentType(), j + i);
System.arraycopy(obj, 0, obj1, flag ? 0 : i, j);
return obj1;
}
/**
* 扩充数组对象
* @param obj
* @param i
* @param flag
* @return
*/
static public Object expand(Object obj, int i) {
return expand(obj, i, true);
}
/**
* 随机返回数组内容
* @param obj
*/
static public void mixElements(Object obj) {
int i = Array.getLength(obj);
for (int k = 0; k < i; k++){
int j = getRandom(k, i - 1);
Object obj1 = Array.get(obj, j);
Array.set(obj, j, Array.get(obj, k));
Array.set(obj, k, obj1);
}
}
static public Random getRandomObject() {
return rand;
}
static public int getRandom(int i, int j) {
return i + rand.nextInt((j - i) + 1);
}
private int hash(Object obj) {
int h = obj.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
public int hashCode() {
return hash(objArray.getClass());
}
public int size() {
return size;
}
/**
* 返回当前数组对象
* @return
*/
public Object[] getObjectArray() {
return (Object[]) objArray;
}
public static void main(String[] args) {
/**//*TestBean[] tb = new TestBean[3];
for (int i = 0; i < tb.length; i++) {
tb[i] = new TestBean();
tb[i].setName("name" + i);
tb[i].setId(i);
}
//直接载入已有数组对象
ArrayUtil arrayUtil = ArrayUtil.getInstance(tb);
TestBean tb1 = new TestBean();
// arrayUtil.add(tb[0]);
arrayUtil.remove(tb[0]);
// arrayUtil.remove(tb[2]);
System.out.println(arrayUtil.contains(tb1));
System.out.println(((TestBean) arrayUtil.get(0)).getName());
System.out.println(arrayUtil.size());
// 打乱数组
arrayUtil.mixElements();
for (int i = 0; i < arrayUtil.size(); i++) {
System.out.println(((TestBean) arrayUtil.get(i)).getName());
}*/
//生成TestBean的数组实例,初始容量为5
ArrayUtil arrayUtil = ArrayUtil.getInstance(TestBean.class,5);
TestBean t = new TestBean();
t.setName("test");
//在数组载入t的实例
arrayUtil.add(t,0);
TestBean t1 = new TestBean();
t1.setName("test1");
arrayUtil.add(t1,1);
arrayUtil.add(t,2);
arrayUtil.add(t,3);
arrayUtil.add(t,4);
//会自动增加数组容量
arrayUtil.add(t);
//显示索引5数据
System.out.println(((TestBean)arrayUtil.get(5)).getName());
//截取索引1-3,显示1数据
System.out.println(((TestBean)arrayUtil.sub(1, 3)[1]).getName());
}
}
通过例子我们可以发现,只是简单的几行代码,就令Array发挥出我们需要借助他人集合类才能完成的功能。而这些,却本来是我们也可以轻易做到的。