Java的数组是一个静态的概念,必须先初始化之后才能够使用。初始化又分为动态的初始化静态的初始化,以int[]数组为例

1.int[] a;如此定义,仅仅是在栈区定义了一个变量(变量往往存在于栈区),此时数组也没有初始化,变量并未指向堆内存中的任何地方

2.int[] a=new int[5];如此定义便是数组动态的初始化,初始化长度为5。在栈区定义了一个变量a,在堆内存创建了一个数组对象,这个数组对象一共有5个元素,但是这个5个元素都是null,变量a指向这个数组空对象。

3.int[] a=new int[]{1,2,3,4,5};如此定义便是数组静态的初始化,指定了数组中各个元素。相当于在栈区定义了变量a,在堆内存中创建了一个数组对象,这个数组对象中一共5个元素,分别是1,2,3,4,5.栈区的变量a指向了堆内存中的数组对象.

接下来看一段代码

public class InitialArray {

    public static void main(String[] args) {
        int[] a=new int[]{1,2,3,4,5};
        int[] b=a;
        System.out.println("数组的长度是"+b.length);
    }

}

执行结果:数组的长度是5

这段代码中有两个数组,数组变量a和数组变量b,可以看到数组a已经初始化了,但是数组b还没有进行初始化。但是他依然可以使用(使用方法b.length),是违反了我们数组在使用之前必须先初始化的定义了吗?其实并不是这样的,在执行“int[] a=new int[]{1,2,3,4,5};”这段代码的时候,由上面可以知道,在栈区定义了一个变量a,在堆内存创建了一个数组对象{1,2,3,4,5},在执行“int[] b=a;”的时候,发生的动作是在栈区新创建了一个变量b,指向了原来变量a指向的对象。此时变量a和变量b都执行堆内存中的数组对象。

再看下一段代码

public class InitialArray {

    public static void main(String[] args) {
        int[] a=new int[]{1,2,3,4,5};
        int[] c=new int[]{1,2,3,4,5,6};
        a=c;
        System.out.println("数组的长度是"+a.length);
    }

}

执行结果:数组的长度是6

这段代码的情况是在堆内存静态初始化了两个int类型的数组对象,在栈区中定义了变量a和b,分别指向这两个数组对象。执行a=c;之后是将原来c变量指向的对象赋值给a变量。这样做的结果是将{5,6,7,8,9,10}数组对象分别指定给变量a和变量c,因为堆内存中的对象是不能直接操作的,往往通过变量来实现。而原来a变量指向的数组对象则会由于失去引用变成一种孤立的状态,假如尝试键都没有变量去指向{1,2,3,4,5}这个对象的话,那么时间一长,这个对象就会变成垃圾对象在Java的垃圾回收机制下回收。

 再看下一段代码:

class Student{
    int score,age;
    public Student(int score,int age){
        this.score=score;
        this.age=age;
    }
}
public class InitialArray {

    public static void main(String[] args) {
        Student[] students=new Student[3];
        Student xiaoming=new Student(98,15);
        Student xiaohua=new Student(97,14);
        Student xiaohong=new Student(95,16);
        students[0]=xiaoming;
        students[1]=xiaohua;
        students[2]=xiaohong;
        System.out.println("小明的成绩为"+xiaoming.score);
        System.out.println("小明的成绩为"+students[0].score);
    }

}

执行结果:

小明的成绩为98
小明的成绩为98

这段代码创建了一个Student类,在main方法中又动态初始化了一个Student类型的引用类型数组(如int[],float[],double[]这些是基础类型数组)。相当于在栈区创建了一个引用类型变量students,在堆内存区创建了一个长度为3的数组对象,students数组指向该对象。初始化之初,数组中的所有元素都为空。然后在栈区创建了3个引用类型的变量,在堆内存区创建了与栈区引用变量相对应的对象,最后将xiaoming指定的对象赋值给students[0],将xiaohua指定的对象赋值给students[1],将xiaohong指定的对象赋值给students[2]。最终结果便是变量xiaoming和students[0]都指向同一块内存对象。xiaoming.score的值,也就是students[0].score的值。

问题:引用变量什么时候以栈区变量的形式出现,什么时候以内存对象的形式出现呢?引用变量本质上上一个指针,当students[0]=xiaoming时仅仅只是改变指针的指向,当xiaoming.score执行的时候,xiaoming就会以内存对象的形式出现了。

tips:Java语言避免直接修改堆内存中的数据以保证程序的健壮性,如果程序直接访问或修改堆内存中的数据可能会破坏数据的完整性,导致程序crash