在《数组和数组列表》那篇随笔里我们定义了一个int类型的数组列表,但是这样实际上是有问题的,在日后的开发中我们使用的数组列表实际上并不一定是int类型的,甚至于,还不一定会是基本数据类型的。那这个时候,按照原来的方法,我们在开发中每要定义一个数组列表,我们就要重写一遍,这样做实际上是非常不友好的。那么有什么方法来解决这一问题呢,这样我们便引出了泛型这个概念
泛型
什么是泛型?泛型简单来理解实际上就是一个类类型,它是表示一个类的类型,而不具体表示某一个对象。由于在此重点是数组列表,关于泛型的其他便不再展开。
泛型的数组列表
与前文类似,基于泛型的数组列表也是由接口类和继承类来实现。参考代码如下:
1 public interface C<E> { 2 3 4 /** 5 * 添加一个元素 6 */ 7 public void store(E element); 8 9 /** 10 * 获取数组长度 11 */ 12 public int getSize(); 13 14 /** 15 * 修改元素 16 */ 17 public void upData(int index, E newElement); 18 19 /** 20 * 取出元素 21 */ 22 public E getElement(int index); 23 24 /** 25 * 删除元素 26 */ 27 public void delete(int index); 28 }
接口的定义
在定义泛型的数组列表接口中,用一对尖括弧<>来表示要在此传入的具体类型,其中的E表示的是Element,即元素,也就是这个数组列表具体是一个什么类型的数组列表。
public class D<E> implements C<E> { private int count; // 保存数组的长度 private Object data[]; //创建一个数组 @Override public void store(E element) { // TODO Auto-generated method stub // 创建一个临时数组 Object[] temp = new Object[count + 1]; // 将原数组内容复制到临时数组中 for (int i = 0; i < count; i++) { temp[i] = data[i]; } data = temp; //添加新的元素 data[count] = element; //让数组长度加一 count++; } @Override public int getSize() { // TODO Auto-generated method stub return count; } @Override public void upData(int index, E newElement) { // TODO Auto-generated method stub data[index] = newElement; } @Override public E getElement(int index) { // TODO Auto-generated method stub return (E)data[index]; } @Override public void delete(int index) { // TODO Auto-generated method stub //创建一个临时数组 Object temp[] = new Object[count-1]; //将删除项前的元素复制到临时数组中 for(int i = 0; i < index-1; i++){ temp[i] = data[i]; } //将删除项后的元素复制到临时数组中 for(int i = index-1; i < count-1; i++){ temp[i] = data[i+1]; } data = temp; //数组长度减一 count--; } }
继承类的实现
在实现继承类的过程中,有几点需要注意的。首先是数组的创建,因为不能确定实际上是要创建一个什么类型的数组,此时已经不能创建int型的了,那应该创建什么类型的呢?可能我们会想创建一个E类型的数组,但实际上这会报错
一个解决方案就是创建一个Object类型的数组,因为Object类是所有类型的父类,在我们需要得到数组中一个具体的值的时候,再将这个数组项取出强制转型为E类型并传出。事实证明,这是可行的。
另外还有一个问题,就是临时数组的创建。在每次往数组中增加一个元素时创建一个临时数组并更新原数组,这种逻辑是很清晰的,但是一旦数组的长度高达成千上万时,这样便不可取了。它会消耗代价很高的空间和时间。那又什么办法去解决呢?
优化的方法很多,我在这里使用的方法仅供参考。增加一个判断,一次创建一个具有上限的临时数组,当增加的元素达到临时数组上限时,再次扩充这个上限。代码实现如下:
1 public class D<E> implements C<E> { 2 3 private int count; // 保存数组的长度 4 private Object data[] = new Object[0]; //创建一个数组 5 6 @Override 7 public void store(E element) { 8 // TODO Auto-generated method stub 9 10 if(count==data.length){ 11 // 创建一个临时数组 12 Object[] temp = new Object[count + 1]; 13 14 // 将原数组内容复制到临时数组中 15 for (int i = 0; i < count; i++) { 16 17 temp[i] = data[i]; 18 19 } 20 21 data = temp; 22 } 23 24 25 26 //添加新的元素 27 data[count] = element; 28 29 //让数组长度加一 30 count++; 31 32 } 33 34 @Override 35 public int getSize() { 36 // TODO Auto-generated method stub 37 return count; 38 } 39 40 @Override 41 public void upData(int index, E newElement) { 42 // TODO Auto-generated method stub 43 data[index] = newElement; 44 45 } 46 47 @Override 48 public E getElement(int index) { 49 // TODO Auto-generated method stub 50 return (E)data[index]; 51 } 52 53 @Override 54 public void delete(int index) { 55 // TODO Auto-generated method stub 56 57 //创建一个临时数组 58 Object temp[] = new Object[count-1]; 59 60 //将删除项前的元素复制到临时数组中 61 for(int i = 0; i < index-1; i++){ 62 temp[i] = data[i]; 63 } 64 65 //将删除项后的元素复制到临时数组中 66 for(int i = index-1; i < count-1; i++){ 67 temp[i] = data[i+1]; 68 } 69 70 data = temp; 71 72 //数组长度减一 73 count--; 74 } 75 76 }
测试运行
1 public class Client { 2 3 4 public static void main(String[] args) { 5 System.out.println("实例化一个数组列表d"); 6 D<Integer> d = new D<Integer>(); 7 System.out.println("*******添加项************"); 8 for (int i = 0; i < 5; i++) { 9 d.store(i); 10 System.out.println("d的第" + i + "项为:" + d.getElement(i)); 11 } 12 System.out.println("数组长度为" + d.getSize()); 13 System.out.println("**********删除项***************"); 14 d.delete(2); 15 for (int i = 0; i < d.getSize(); i++) { 16 System.out.println("d的第" + i + "项为:" + d.getElement(i)); 17 } 18 System.out.println("数组长度为" + d.getSize()); 19 System.out.println("***********更新项*************"); 20 d.upData(3, 15); 21 for (int i = 0; i < d.getSize(); i++) { 22 System.out.println("d的第" + i + "项为:" + d.getElement(i)); 23 } 24 System.out.println("数组长度为" + d.getSize()); 25 26 } 27 28 }
运行结果
实例化一个数组列表d *******添加项************ d的第0项为:0 d的第1项为:1 d的第2项为:2 d的第3项为:3 d的第4项为:4 数组长度为5 **********删除项*************** d的第0项为:0 d的第1项为:2 d的第2项为:3 d的第3项为:4 数组长度为4 ***********更新项************* d的第0项为:0 d的第1项为:2 d的第2项为:3 d的第3项为:15 数组长度为4