深化Java基础之——数组与内存控制

来源:互联网 发布:二手域名 编辑:程序博客网 时间:2021/06/19 15:05
作为一个程序猿,大家对数组一定不陌生。平时使用的也比较多,但是往往越简单的东西,可能越会容易忽略一些细节。

下面是对数组相关知识的一个学习总结,如有不对的地方,欢迎来指正。

数组的初始化

 1、Java数组是静态的

  Java数组是静态的,只有在初始化过后才能使用,而Java数组一旦进行初始化之后,其长度就固定了,不可再改变。

  Java数组的初始化有两种方式:

  静态初始化:由程序员在定义数组时,显示的指定每个元素的值,数组长度由系统决定

  动态初始化:程序员直接指定数组的长度,由系统为数组元素分配初始值

  动态初始化,系统分配元素初始值规则:

    基本类型中的整数类型(byte, int, short, long):初始化为0;

    基本类型中的浮点类型(float, double):初始化为0.0;

      基本类型中的字符类型(char):初始化为'\u0000';

    基本类型中的布尔类型(boolean):初始化为false;

    引用类型(类、接口、数组):初始化为null;

//第一种静态初始化方式,长度为2String[] str = new String{"java基础","数组初始化"}; 
//第二种静态初始化方式,长度为3String[] str2 = {"静态","内存结构","java"};
//动态初始化方式,长度为4String[] str3 = new String[4];

//
Java语言允许通过length方法获取数组的长度
System.out.println("str数组长度为:" + str.length);
System.out.println("str2数组长度为:" + str2.length);
System.out.println("str3数组长度为:" + str3.length);

   数组变量只是一个引用类型的变量,不是数组本身,而是指向堆内存中的数组对象,通过下面这个图更清楚的了解一下数组的内存分配

 上述的三个数组初始化完成之后,长度就被分别固定为2,3,4,不可改变。但是这里会有一个数组变量引用的改变,造成数组长度可改变的假象。

str = str2;str3 = str2;System.out.println("str数组长度为:" + str.length);System.out.println("str3数组长度为:" + str3.length);//改变str3中的一个元素值str3[1] = "JVM";System.out.println(str2[1]);

上述代码的执行结果为:str数组长度为:3

                               str3数组长度为:3

                               JVM

看起来好像是str和str3数组的长度都被改变了,那么内存中真正发生了什么事情呢?请看下面的图:

当执行完前面两行数组变量赋值后,str,str3数组引用变量都指向了原来的str2数组,堆内存中的其他两个数组对象会被当做垃圾对象回收掉。

所以对三个数组变量的操作,实际上都是操作的同一个数组对象(这里有点类似于C/C++中的指针),所以数组中第二个元素也被替换成"JVM"。

这里就产生了数组初始化后长度发生改变的假象,实际上是指向了其他数组对象,原来数组对象长度并没有改变。

 

2.数组一定要初始化吗?

通过上面的例子,大家应该明白了数组在内存中的分配机制,那么对于这个问题也就好理解了。

对于数组变量和数组对象这里一定要区分清楚,数组变量通常是存储在栈内存的,类似于C语言中的指针,真正意义上的数组初始化,就是在堆中为数组对象分配内存空间,初始化之后就变成了一个有效的数组对象,只要一个数组变量指向这个有效数组对象,程序中便可使用该数组。通过如下代码来理解一下:

 1 public static void main(String[] args){ 2        //静态初始化一个int类型数组   3        int[] nums = new int{1, 2, 3, 4}; 4        //定义一个int类型的数组变量,不初始化 5        int[] temp; 6        //输出nums数组中一个元素 7        System.out.println("nums数组第二个元素为:" + nums[1]); 8        //让temp数组变量指向nums所引用的数组对象 9        temp = nums;10        //更改temp数组的第二个值,这里已经可以使用temp数组11        temp[1] = 5;12        //nums数组的第二个元素值为513        System.out.println("nums数组第二个元素为:" + nums[1]);14 }

代码第5行并没有对temp进行初始化,而是在第9行,让其指向了一个有效的数组对象,这时nums和temp两个变量指向的是同一块内存,这样便可以使用temp数组。

关于引用数组的初始化在下面的没有多维数组中顺便总结。

使用数组

没有多维数组

  Java允许将多维数组当做一维数组处理。对于int[][] nums 类型的数组,就是元素类型为int[] 的一维数组,nums数组的每个int[] 型元素再指向内存中其他的int型数据。

对于nums可以只初始化最左边的维数,nums = new int[4][],这些元素还要进一步初始化,让这4个int[] 型元素分别指向4个有效的数组对象,看如下例子。

1 int[][] a = new int[4][];2 //4个引用类型元素,所以会输出4个null3 System.out.println(Arrays.toString(a));4 //初始化a数组前两个元素5 a[0] = new int[]{1, 2};6 a[1] = new int[]{3, 4, 5};7 //输出a数组第二个元素指向的内存空间的第3个元素8 System.out.println(a[1][2]);

注释其实写的比较清楚了,为了更深刻的理解,结合代码来看下面的内存分配图:

因为是a数组元素是引用类型,所以系统初始化为null,前两个元素在5、6行又分别初始化,所以指向了其他的内存空间。

通过上面的分析可以看出,多维数组的本质依然是一维数组,当然一维数组的元素也可以是二维数组,这样就是三维数组,以此类推。

在Java程序中使用数组,应多从内存控制的角度来把握程序。

0 0