一、背景
数组在实际的系统开发中用的越来越少了,我们只有在阅读某些开源项目时才会看到数组的使用。在Java中,数组与List、Set、Map等集合类相比,后者使用起来方便,但是在基本数据类型处理方面,数组还是占优势的,而且集合类的底层也都是通过数组实现的。
我们大家都知道,在Java中数组是定长的,一旦初始化以后,就不可以改变其长度,而这在实际应用中是不方便的。举例来说,如果要对班级学生的信息进行统计,因为我们不知道一个班级会有多少学生(随时有入学、退学、转学的学生),所以需要一个足够大的数组来容纳所有的学生(当然,在实际应用场景中,你可以用List或者其他的集合类,本文在此只讨论数据)。那么,究竟需要多大才算足够大呢?事实上,“足够大”只是一个相对的概念,并没有确定的值。所以,当“足够大”变成“足够小”的时候,就会超出数组的最大容量,如何解决呢?那就给数组扩容吧,也许看到此处的朋友会问,你这不是和前面所说的矛盾么?请不要纠结,我这里所说的给数组扩容,只是“婉转”地给数组扩容。那么,怎么个“婉转”扩容呢?还是从例子说起。
二、实例展示
假设一个班级最初规定只能容纳60个学生,但是由于有几个转学的学生突然插进来,整个班级的学生人数达到了80人,这种情况很正常呢,想想我们高中所在的那些强化班就知道是怎么回事了。
第一,先定义一个学生的属性类:Student
public class Student {
/**
* 学生编号
*/
private long studentId;
/**
* 学生姓名
*/
private String name;
/**
* 学生年龄
*/
private int age;
/**
* 学生性别:0-男,1-女
*/
private int gender;
/**
* 学生所在班级
*/
private String ownerClass;
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public String getOwnerClass() {
return ownerClass;
}
public void setOwnerClass(String ownerClass) {
this.ownerClass = ownerClass;
}
}
第二、编写给数组扩容的工具类:ArrayExtendCapacityUtil
public class ArrayExtendCapacityUtil {
/**
* 将数组进行扩容
*
* @param datas
* @param newLen
* @return
*/
public static <T> T[] extendCapacity(T[] datas, int newLen){
//负值校验
newLen = newLen < 0 ? 0 : newLen;
//生成一个新的数组,并copy原来的值
return Arrays.copyOf(datas, newLen);
}
}
第三、编写测试类:ArrayExtendCapacityMain
import java.util.ArrayList;
import java.util.List;
public class ArrayExtendCapacityMain {
public static void main(String args[]){
//一个班规定60个学生
Student[] num = new Student[60];
System.out.println("初始化:" + num.length);
System.out.println("最后一个学生的编号:" + converData(num.length).get(num.length-1).getStudentId());
//增加20个学生
num = ArrayExtendCapacityUtil.extendCapacity(num, 80);
System.out.println("扩容后:" + num.length);
System.out.println("扩容后最后一个学生的编号:" + converData(num.length).get(num.length-1).getStudentId());
}
private static List<Student> converData(int capacity){
List<Student> students = new ArrayList<Student>();
for(int i=0;i<capacity;i++){
Student student = new Student();
student.setStudentId(i);
student.setName(i+"-King");
student.setAge(i+10);
student.setGender(i % (i+10) == 0 ? 0 : 1);
student.setOwnerClass(i + "-class");
students.add(student);
}
return students;
}
}
三、测试结果
初始化:60
最后一个学生的编号:59
扩容后:80
扩容后最后一个学生的编号:79
四、测试结果分析
本文实例中采用的是Arrays数组工具类的copyOf方法,产生了一个newLen长度的新数组,并把原来的值拷贝进去,然后就可以对超长的元素进行赋值。
通过这样的方式,曲折地解决了数组的变长问题。其实,集合的长度自动维护功能的原理与此类似,在实际开发中,如果确实需要变长的数据集,数组也是在考虑范围之内的,不能因为数组是固定长度就将其否定。在这里,我可以直接借用一个结论:对基本数据进行求和计算时,数组的效率是集合的10倍。有兴趣的朋友可以自己证明一下这个结论。