数组

一、何谓数组?

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类是两个不同的类,所具备的方法和行为可能不一致,具体看参考源码

原文地址:https://www.cnblogs.com/liupiao/p/9273636.html