`
g21121
  • 浏览: 684242 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java中的数组

 
阅读更多

         所谓数组,就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。数组是在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来的一种形式。这些按序排列的同类数据元素的集合称为数组。

        数组使我们在程序开发过程中经常会使用到的一个简单集合,所谓简单就是在同一个数组集合中所有元素必须是相同类型,不同的开发语言中都有数组这个概念,利用数组我们可以把一类变量进行收集在一起进行使用。

        在Java中有一维数组和多维维数组这两种种数组结构,一维数组是我们经常使用的,下面就从使用的角度来介绍数组,以下内容以一位数组为例。

 

        1.声明数组

        数组的声明有如下两种形式:

int[] intArray;
int intArray[];

        此时声明的数组无法使用,使用'new'关键字创建数组和'='赋予创建的引用,例如:

int size=10;//数组大小、长度

int[] intArray=new int[size];//声明一个int基本数据类型数组,长度为size

        声明数组的格式为:数组类型 数组名 = new 数组类型[数组大小];

        此时我们所讲的数组长度或大小指的是该数组中的元素数量。

 

        当我们不主动声明该数组的长度时,编译器会给出错误提示:

Variable must provide either dimension expressions or an array initializer

        也就是说如果这个数组我们想使用它,就需要两个必要条件,一是声明该数组的类型,二是声明数组的长度(大小)。

        但特殊情况下可以不必显式声明数组长度,那就是在声明数组时直接为数组初始化赋值,例如:

int[] intArray=new int[]{};//声明一个int基本数据类型数组,长度为0

int[] intArray=new int[]{1,2,3};//声明一个int基本数据类型数组,长度为3

        当然这种数组是一个空的数组,我们无法使用它,在实际使用中用处不大。

        当我们强制赋值的时候会抛出数组越界异常:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0

 

        2.数组初始化

        1)动态初始化:数组定义与为数组分配空间和赋值的操作分开进行;

        动态初始化比较好理解,也是我们最常用的,如:

int[] intArray=new int[3];//声明一个int基本数据类型数组,长度为3
//开始赋值
intArray[0]=1;
intArray[1]=2;
intArray[2]=3;

 

        2)静态初始化:在定义数字的同时就为数组元素分配空间并赋值;

        静态初始化就是在创建数组时即为其赋值,这种方式常用于一些常量值使用上,如下:

int[] intArray1 = new int[] { 1, 2, 3 };// 声明一个int基本数据类型数组,长度为3,初始值为1,2,3
int[] intArray2 = { 1, 2, 3 };// 声明一个int基本数据类型数组,长度为3,初始值为1,2,3

 

        3)默认初始化:数组是引用类型,它的元素相当于类的成员变量,因此数组分配空间后,每个元素也被按照成员变量的规则被隐式初始化。

        默认初始化也就是我们声明数组后不去主动赋值,直接使用该类型的默认值,如下:

int[] intArray=new int[3];//声明一个int基本数据类型数组,长度为3
System.out.println(intArray[0]);
System.out.println(intArray[1]);
System.out.println(intArray[2]);

//打印结果:
0
0
0

 

        3.数组的结构

        既然数组是通过'new'关键字来创建的,那么它就会在内存中开辟一块区域来存储该数组,然而数组在内存中是如何存储的呢?结构又是什么样的呢?以下几部分内容应该是本文的重点。

        以基本类型数组为例,代码如下:

int[] intArray=new int[3];//声明一个int基本数据类型数组,长度为3
//开始赋值
intArray[0]=98;
intArray[1]=99;
intArray[2]=100;

 

        数组的存储结构如图所示:



        当数组为多维时,以二维数组为例:

int[][] intArray = new int[3][3];
intArray[0] = new int[3];
intArray[1] = new int[4];
intArray[2] = new int[5];
// 第一个数组赋值
intArray[0][0] = 98;
intArray[0][1] = 99;
intArray[0][2] = 100;
// 第二个数组赋值
intArray[1][0] = 98;
intArray[1][1] = 99;
intArray[1][2] = 100;
intArray[1][3] = 101;
// 第三个数组赋值
intArray[2][0] = 98;
intArray[2][1] = 99;
intArray[2][2] = 100;
intArray[2][3] = 101;
intArray[2][4] = 102;

for (int i = 0; i < intArray.length; i++) {
	System.out.println("|--" + i);
	for (int j = 0; j < intArray[i].length; j++) {
		System.out.println("  |--" + intArray[i][j]);
		}
	}
}

        打印结果为:

|--0
  |--98
  |--99
  |--100
|--1
  |--98
  |--99
  |--100
  |--101
|--2
  |--98
  |--99
  |--100
  |--101
  |--102

 

        此时该二维数组在内存中的结构如图:



 

        多维数组也是类似的道理和结构,我在此就不再举例了。

 

        4.数组的内存分配

       虽然我们已经了解了数组的基本结构,但是对于数组的内部实现机理和存储方式还不清楚。

       通过下图可以很清晰的了解到数组在Java虚拟机中,是个真正的对象!



        和其他对象一样,数组总是存储与虚拟机的堆内存中,同样,和普通对象一样,实现的设计者将决定数组在堆中的表现形式。数组也拥有一个与它们的类相关联的Class实例,所有具有相同纬度和类型的数组都是同一个类的视力,而不管数组的长度是多少。例如之前例子里的几个int型数组。

        众所周知通过intArray.length可以获取intArray数组的长度。但是对于String或其他类的大小或长度却是通过length()方法获取到的,那么length是否为数组的成员变量那,如果是那么数组的类类型又是什么,如果不是,那这个length是哪里来的?

        先来看一段代码:

int[] intArray = new int[3];// 声明一个int基本数据类型数组,长度为3,初始值为1,2,3
Class arrayClass = intArray.getClass();
Field[] fields = arrayClass.getDeclaredFields();
if (fields != null && fields.length > 0) {
	for (Field field : fields) {
		System.out.println(field.getName());
	}
} else {
	System.out.println("intArray没有成员变量");
}
System.out.println("-----------------------------");

System.out.println("intArray引用地址为:" + intArray);
System.out.println("intArray全名为:       " + arrayClass.getName());
System.out.println("intArray类名为:       " + arrayClass.getSimpleName());
System.out.println("intArray父类全名为:" + arrayClass.getSuperclass().getName());
System.out.println("intArray父类类名为:" + arrayClass.getSuperclass().getSimpleName());

        打印结果:

intArray没有成员变量
-----------------------------
intArray引用地址为:[I@2f9ee1ac
intArray全名为:       [I
intArray类名为:       int[]
intArray父类全名为:java.lang.Object
intArray父类类名为:Object

        通过打印出来的结果发现:

        1.数组并没有成员变量,也就是说数组根本没有length这个属性,在JVM中是通过arrayLength这个命令来直接获取该数组长度。

        2.数组的全类名为[I。

        3.简单名称(或类名)为int[],之所以为int[],是因为api中说如果调用该方法的对象为数组的话会自动加上[]。

        4.父类为Object。

        数组类的名称由两部分组成:数组类的名称由两部分组成:每一维用一个中括号"["表示,用自负或者字符串表示元素类型。比如,元素类型为int型的一维数组类名则为"[I",也就与之前的打印结果相吻合;元素类型为byte的三维数组的名称就为"[[[B";元素类型为Object的二维数组为"[[Ljava/lang/Object"。

 

        既然数组的值也是存放在堆内存中的,那么当此数组不再被引用时,它也会变成垃圾,等待垃圾处理器处理。那么我们做如下测试:

        1)定义两个数组:

int[] intArray1 = new int[3];
intArray1[0] = 98;
intArray1[1] = 99;
intArray1[2] = 100;
int[] intArray2 = new int[4];
intArray2[0] = 98;
intArray2[1] = 99;
intArray2[2] = 100;
intArray2[3] = 101;
System.out.println("intArray1引用地址:" + intArray1);
System.out.println("intArray2引用地址:" + intArray2);
//修改两个数组
intArray2 = intArray1;
intArray1 = new int[3];
System.out.println("-----------------------------");
System.out.println("intArray1引用地址:" + intArray1);
System.out.println("intArray2引用地址:" + intArray2);

//打印结果
intArray1引用地址:[I@2a9931f5
intArray2引用地址:[I@2f9ee1ac
-----------------------------
intArray1引用地址:[I@67f1fba0
intArray2引用地址:[I@2a9931f5

        从打印结果就可以直接看到intArray2最后持有了intArray1的引用,而intArray1则重新创建了一个新的数组并持有新的引用,而"[I@2f9ee1ac"这个地址上原来的数组数据就变成了垃圾,将来会被清除。



 

        多维数组被表示为数组的数组,最终的以一个二维数组为例,在Java虚拟机中他的内存分配表现形式为:


        通过以上数组的学习与了解相信对数组的结构与存储已经有了一定的了解,更深入的层次还需要自己去不断学习与深入,希望我们可以进一步交流。
 

5
1
分享到:
评论
1 楼 我菜ButNeverGiveUp 2014-10-29  
总结的很好,沙发

相关推荐

Global site tag (gtag.js) - Google Analytics