深入分析Java数组

数组的基本介绍:

    数组对于每一门编辑应语言来说都是重要的数据结构之一;

数组基本用法:

声明数组变量

   首先必须声明数组变量,才能在程序中使用数组。

   下面是声明数组变量的语法:

 type[] values; // 首选的方法 或type values[]; // 效果相同,但不是首选方法

创建数组

    Java语言使用new操作符来创建数组,语法如下:   

   values = new type [size];

   上面的语法语句做了两件事:

    一、使用type [size]创建了一个数组。

    二、把新创建的数组的引用赋值给变量values。

  数组变量的声明,和创建数组可以用一条语句完成,如下所示:

type[] values = new type[10];

    另外,你还可以使用如下的方式创建数组。

  type[] values = {value0, value1, ..., value10};

  数组的元素是通过索引访问的。数组索引从0开始,所以索引值从0到values.length-1。

实例:

   下面的语句首先声明了一个数组变量myList,接着创建了一个包含10个double类型元素的数组,并且把它的引用赋值给myList变量。

 double[] myList = new double[10];

  下面的图片描绘了数组myList,这里myList数组里有10个double元素,它的下标从0到9。

   blob.png

处理数组

   数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者foreach循环。

常见的数据错误:

  使用数组常见错误一:编译出错,没有声明数组初始化大小;

  int []array=new int[];

  使用数组常见错误二。数组越界。

  int []array=new int[1];
  array[2]=1;

  blob.png

   使用数组常见错误三。语法错误。

    blob.png

二、数组的深入分析:

数组的内存分配:

     java中的数组是用来存储同一种数据类型的数据结构,一旦初始化完成,即所占的空间就已固定下来,初始化的过程就是分配对应内存空间的过程。即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变。 要向改变数组的空间必须扩容数组操作如下:

 //从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
  Arrays.copyOf(T[] original, int newLength);
  或者是System.arraycopy(elementData, index, elementData, index + 1, size - index);

   当仅定义一个数组变量(int[] numbers)时,该变量还未指向任何有效的内存,因此不能指定数组的长度,只有对数组进行初始化(为数组元素分配内存空间)后才可以使用。 

   数组初始化分为静态初始化(在定义时就指定数组元素的值,此时不能指定数组长度)和动态初始化(只指定数组长度,由系统分配初始值)。

  //静态初始化

int[] numbers = new int[] { 3, 5, 12, 8, 7 };
String[] names = { "Miracle", "Miracle He" };//使用静态初始化的简化形式

 //动态初始化

int[] numbers = new int[5];
String[] names = new String[2];

  当初始化完毕后,就可以按索引位置(0~array.length-1)来访问数组元素了。 

当使用动态初始化时,如在对应的索引位未指定值的话,系统将指定相应数据类型对应的默认值(整数为0,浮点数为0.0,字符为’\u0000’,布尔类型为false,引用类型(包括String)为null)。

public class TestArray {
    public static void main(String[] args) {
        String[] names = new String[3];
        names[0] = "Miracle";
        names[1] = "Miracle He";
        /*
        for(int i = 0; i < names.length;i++) {
            System.out.print(names[i] + " ");
        }
        */
        //还可以使用foreach来遍历
        for(String name : names) {
            System.out.print(name + " ");
        }
    }
}

  结果如下:  

Miracle Miracle He null 

Miracle Miracle He null

数组在内存中如何储存

如图:

 blob.png

     数组引用变量是存放在栈内存(stack)中,数组元素本质是一个对象,是存放在堆内存(heap)中。通过栈内存中的指针指向对应元素的在堆内存中的位置来实现访问。 

基本数据类型的数组在内存分配情况:

public class TestPrimitiveArray {
    public static void main(String[] args) {
        //1.定义数组
        int[] numbers;
        //2.分配内存空间
        numbers = new int[4];
        //3.为数组元素指定值
        for(int i = 1;i <= numbers.length;i++) {
            numbers[i] = i ;
        }
    }
}

   内存分布如图:

    blob.png

   从图中可看出数组元素直接存放在堆内存中,当操作数组元素时,实际上是操作基本类型的变量。

2、存放引用类型数组在内存中如何储存

  先来再看一段存储引用类型数组的实例:

class Person {
    public int age;
    public String name;
    public void display() {
        System.out.println(name + "的年龄是: " + age);
    }
}
public class TestReferenceArray {
    public static void main(String[] args) {
        //1.定义数组
        Person[] persons;
        //2.分配内存空间
        persons = new Person[2];
        //3.为数组元素指定值
        Person p1 = new Person();
        p1.age = 28;
        p1.name = "Miracle";
        Person p2 = new Person();
        p2.age = 30;
        p2.name = "Miracle He";
        persons[0] = p1;
        persons[1] = p2;
        //输出元素的值
        for(Person p : persons) {
            p.display();
        }
    }
}

   元素为引用类型的数组,在内存中的存储与基本类型完全不一样。 

   此时数组元素存放引用,指向另一块内存,在其中存放有效的数据。如图:

   blob.png

  在数组参数传递的时候,数组是作为引用参数,传递的是数组的引用指针,将数组引用传递给另一数组引用,但仍然不能改变数组长度(仅仅只是调整数组引用指针的指向)。

二维数组及用法

  用法: 定义方式和一维数组类似,如下:

type arrayName[ ][ ];  
type [ ][ ]arrayName;

 1、初始化:

  静态初始化:

int intArray[ ][ ]={{1,2},{2,3},{3,4,5}};

 2、动态初始化:

    int a[ ][ ] = new int[2][3];
   a[0] = new int[3];
   a[1] = new int[3];
   a[0][1] = new int[4];
   a[0][2] = new int[4];
   a[0][3] = new int[4];

  对二维引用类型的数组,必须首先为最高维分配引用空间,然后再顺次为低维分配空间。而且,必须为每个数组元素单独分配空间。

 获取二维数组:

int a[][] = { { 1, 5, 2, 8 }, { 5, 9, 10, -3 }, { 2, 7, -5, -18 } };// 静态初始化一个二维数组

 例子:

int a[][] = { { 1, 5, 2, 8 }, { 5, 9, 10, -3 }, { 2, 7, -5, -18 } };
 for (int i = 0; i < 3; i++) {
  for (int j = 0; j <4; j++) {
     System.out.println(a[i] + "_" + a[i][j]);
  }
}

 输出结果:

[I@901a4f3_1

[I@901a4f3_5

[I@901a4f3_2

[I@901a4f3_8

[I@48b02c5_5

[I@48b02c5_9

[I@48b02c5_10

[I@48b02c5_-3

[I@42049d11_2

[I@42049d11_7

[I@42049d11_-5

[I@42049d11_-18

多维数组内存分配:

以二维数组为例:

public static void main(String[] args) {
// 1.定义二维数组
        int[][] numbers;
        // 2.分配内存空间
        numbers = new int[2][];
        // 可以把numbers看作一维数组来处理
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + ",");// null,null,null
        }
        System.out.println("");
        // 3.为数组元素指定值
        numbers[0] = new int[2];
        numbers[0][1] = 1;
        numbers[1] = new int[2];
        numbers[1][0] = 11;
        numbers[1][1] = 15;
        for (int i = 0; i < numbers.length; i++) {
            for (int j = 0; j < numbers[i].length; j++) {
                System.out.print(numbers[i][j] + ",");
            }
            System.out.println("");
        }
}

结果如下: 

null,null, 

0,1, 

11,15,

以一个图展示这个数组在内存中的存储:

 blob.png

Array类的用法:

    java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。静态方法是属于类的,不是属于类的对象。所以可以直接使用类名加方法名进行调用。Arrays作为一个工具类,能很好的操作数组。下面介绍主要使用的几个函数。


   1.fill方法:

       fill方法主要用来填充数组,这里我们举最简单的int类型吧(其它类型的一样)

     看Arrays的fill源码:

    blob.png

 示例代码:

public static void main(String[] args) {
  int a[] = new int[5];
   // fill填充数组
   Arrays.fill(a, 1);
   for (int i = 0; i < 5; i++)
   // 输出5个1
   System.out.println(a[i]);
}

  结果:1 1 1 1 1 1;

 

  填充部分数组源码:

   blob.png

   示例:

public static void main(String[] args) {
int a[] = new int[5];
// fill填充数组
Arrays.fill(a, 1, 2, 1);
for (int i = 0; i < 5; i++)
// a[1]=1,其余默认为0
System.out.println(a[i]);
}

结果:0 1 0 0 0;

2.sort方法:

  从方法名看都知道是给数组排序,依然用int类型来说,其它类型一样的。

3. equals方法:

  用于比较两个数组中的元素值是否相等,还是看int类型的数组。看Arrays源码

  blob.png

4.binarySearch方法

  通过binarySearch方法能对排序好的数组进行二分查找法操作。看源码如下

 blob.png

5.copyof方法

  复制数组,Arrays的copyOf()方法传回的数组是新的数组对象,所以您改变传回数组中的元素值,也不会影响原来的数组

6……. 方法;



注:在浏览的过程中如果遇到代码样式问题,建议使用Chrome浏览器查看。

发表评论