一、何谓数组?
1.数组是一种复合数据类型,是系列有序数据的集合,特点是数组中每一个数据的数据类型一定是相同的,通过索引可以快速定位数组中元素,获取数组中数据速度非常快。在java中,数组本质上是对象。数组是保存一组对象最有效一种方式,同样数组是一种效率最高的存储和 随机访问对象引用序列的方式,缺点是数组的大小固定,并且在生命周期内部可改变,数组之所以优于泛型之前的容器,是因为数组持有某种具体的类型,可在编译器检查,防止插入类型错误或者抽取不当类型,数组可以持有基本类型,泛型之前的容器则不能,不过由于自动包装机制,使容器看起来具备持有基本类型的能力。也是因为这个导致数组仅存的优势是效率。
1 /** 2 * 数组 3 */ 4 public class Demo{ 5 public static void main(String[] args){ 6 int a[] = new int[10]; 7 System.out.println(a.getClass()); 8 System.out.println(a.getClass().getSuperclass()); 9 } 10 }
结果输出:
class [I class java.lang.Object
从结果可以看出,数组的父类是object,数组的类名class [I,这是java虚拟机生成的一个特殊类。同时也可以看出数组和普通的Java类是不同的,普通的java类是以全限定路径名+类名来作为自己的唯一标示的,而数组则是以若干个[+L+数组元素类全限定路径+类来最为唯一标示的。
2.数组类是否有其他属性和方法呢?以及我们经常用的length字段,是否是数组类的成员属性之一呢?
1 public class Demo{ 2 public static void main(String[] args){ 3 int a[] = new int[10]; 4 Class clazz = a.getClass(); 5 System.out.println(clazz.getDeclaredFields().length); 6 System.out.println(clazz.getDeclaredMethods().length); 7 System.out.println(clazz.getDeclaredConstructors().length); 8 System.out.println(clazz.getDeclaredAnnotations().length); 9 System.out.println(clazz.getDeclaredClasses().length); 10 } 11 }
结果输出:
0 0 0 0 0
结果可知,与我们想的不一样,数组类没有生命任何成员变量、成员方法、构造函数、Annotation甚至连length成员变量这个都没有,它就是一个彻彻底底的空类。length并不是数组类的一个成员属性,那么获取数组长度的方式实际是通过arraylength指令,当编译器在编译int b=a.length的时候,直接做了特殊处理。
二、数组的使用
1.数组的使用非常简单,同其他类一样,需要声明和new。
1 /** 2 * 数组 3 */ 4 public class Demo{ 5 public static void main(String[] args){ 6 int a[] = new int[10];//声明和分配空间 7 Demo demos[] = new Demo[10]; 8 System.out.println(demos[0]); 9 System.out.println(a[0]); 10 a[0]=1; 11 demos[0] = new Demo();//数组的赋值 12 System.out.println(a[0]); 13 System.out.println(demos[0]); 14 } 15 }
结果输出:
null 0 1 com.demo.Demo@6d06d69c
当我们声明一个数组,并分配了内存空间,会给予一个初始值。紧接着可以按我们的意愿进行赋值。当数组是基本类型数组的时候,可以看做生成的数组类的属性为基本类型,存放的即基础类型数据的值,当数据是引用类型的时候,生成数组类的成员属性类型为引用类型,存放的即引用类型数据的引用。数组是引用类型,它的元素相当于类的成员变量,因此给数组分配内存空间后,每个元素也被按照成员变量的规则被隐式初始化。
2.数组的初始化
数组的初始化可分为:动态初始化和静态初始化两种,具体的使用如下:
1 public class Demo{ 2 public static void main(String[] args){ 3 //1.静态初始化,在定义数组的同时给数组分配空间并赋值 4 int a[] = {1,10,2}; 5 Test t[] ={new Test(0),new Test(2),new Test(10)};//数组的大小,自动判定 6 7 //2.动态初始化,数组的空间分配和赋值分开操作 8 int b[] = new int[3]; 9 b[0]=0;b[1]=2;b[3]=10; 10 Test s[] = new Test[3]; 11 s[0] = new Test(10);//可以知道引用类型数组中存放是一个指向我们new的对象的引用 12 s[1] = new Test(100); 13 s[2] = new Test(0); 14 15 } 16 } 17 18 19 class Test{ 20 private int i; 21 public Test(int i) { 22 this.i = i; 23 } 24 }
三、数组的复制问题
数组复制,通常是借助工具类Arrays完成的。数组复制是典型的浅复制
1 /** 2 * 数组复制 3 */ 4 public class Demo{ 5 public static void main(String[] args){ 6 Test []tests = new Test[1];//1定义一个引用类型的数组,tests是一个引用,指向java堆中生成的[Lcom.test.Test对象. 7 Test t1 = new Test(10);//2.new一个Test对象 8 tests[0] = t1; //给数组赋值,可以看做是[Lcom.test.Test对象的一个引用类型属性被赋值,即这个引用类型属性指向我们new的Test的对象 9 tests[0].getData(); 10 //借助工具类进行数组的复制 11 Test [] tests2 = Arrays.copyOf(tests,tests.length); 12 System.out.println("复制的数组的大小:"+tests2.length); 13 tests2[0].getData(); 14 15 t1.setData(1000);//修改数组中的引用指向对象的数据 16 System.out.println("-------------------------"); 17 tests[0].getData(); 18 tests2[0].getData();//结果是两个数组的中数据都发生了变化 19 20 } 21 } 22 23 24 class Test{ 25 private int i; 26 public Test(int i) { 27 this.i = i; 28 } 29 public void getData(){ 30 System.out.println(this.i); 31 } 32 public void setData(int i){ 33 this.i = i; 34 } 35 }
结果输出:
10
复制的数组的大小:1
10
-------------------------
1000
1000
四、数组与List之间的转换
1 /** 2 * 数组与list之间的转换 3 */ 4 public class Demo{ 5 public static void main(String[] args){ 6 int[] a = new int[]{1,2,3,4}; 7 List list = Arrays.asList(a); 8 System.out.println(list.size()); 9 System.out.println(list.get(0)); 10 11 Integer[] b = new Integer[]{1,2,3}; 12 List list2 = Arrays.asList(b); 13 System.out.println(list2.size()); 14 System.out.println(list2.get(0)); 15 } 16 }
结果输出:
1
[I@6d06d69c
3
1
结果可能与很多人想的不一样,造成的原因,需要借助源代码进行理解,查看asList方法的源码
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
注意点:1.参数:T…a,这个参数是一个泛型的变长参数,基本类型是不能被泛型化的,基本类型数组被当成一个对象类处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型
将int改为Integer,结果就完全不一样了。
2.通过Arrays.asList 转换的list,不能进行add操作,因为asList返回的ArrayList是Arrays工具类中的一个内部类,与java.util.ArrayList类是两个不同的类,所具备的方法和行为可能不一致,具体看参考源码