A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

    数组用来存储同一种数据类型的数据,一旦初始化完成,即所占的空间就已固定下来,即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变。当仅定义一个数组变量(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,引用类型为null)
public class TestArray {
   public static void main(String[] args) {
       String[] names = new String[3];
       names[0] = "Miracle";
       names[1] = "Miracle He";
       //以下代码将输出Miracle Miracle He null

       //还可以使用foreach来遍历
       for(String name : names) {
           System.out.print(name + " ");
       }
    }
}
请注意:java中是没有foreach这个关键字的,其语法是for(type item : items)来表示,但foreach只能用于遍历元素的值而不能改变,必须使用for才能实现。
public class TestForEach {
   public static void main(String[] args) {
       int[] numbers = { 3, 5, 12, 8, 7 };
       for(int number : numbers) {
           int num = number * 10;
           System.out.print(num + ",");
       }
       System.out.println("");
       //numbers仍然未发生变化(如果换成for将改变)
       for(int i = 0;i < numbers.length;i++) {
           System.out.print(numbers + ",");
       }
    }
}
以上简单的介绍了数组的初始化和应用,接下来讲详细介绍数组(数组引用和数组元素)在内存中的存放形式。首先给出结论:数组引用变量是存放在栈内存(stack)中,数组元素是存放在堆内存(heap)中,通过栈内存中的指针指向对应元素的在堆内存中的位置来实现访问,以下图来说明数组此时的存放形式。
////////////图一所示///////////
   那什么是栈内存和堆内存呢?我举例作一一解释。当执行方法时,该方法都会建立自身的内存栈,以用来将该方法内部定义的变量逐个加入到内存栈中,当执行结束时方法的内存栈也随之销毁,我们说所有变量存放在栈内存中,即随着寄存主体的消亡而消亡;反之,当我们创建一个对象时,这个对象被保存到运行时数据区中,以便反复利用(因为创建成本很高),此时不会随着执行方法的结束而消亡,同时该对象还可被其他对象所引用,只有当这个对象没有被任何引用变量引用时,才会在垃圾回收在合适的时间点回收,我们说此时变量所指向的运行时数据区存在堆内存中。只有类型兼容(即属于同一数据类型体系且遵守优先级由低到高原则),才能将数组引用传递给另一数组引用,但仍然不能改变数组长度(仅仅只是调整数组引用指针的指向)
public class TestArrayLength {
   public static void main(String[] args) {
       int[] numbers = { 3, 5, 12 };
       int[] digits = new int[4];
       System.out.println("digits数组长度:" +digits.length);//4
       for(int number : numbers) {
           System.out.print(number + ",");//3,5,12,
       }
       System.out.println("");
       for(int digit : digits) {
           System.out.print(digit +",");//0,0,0,0,
       }
       System.out.println("");
       digits = numbers;
       System.out.println("digits数组长度:" +digits.length);//3
    }
}
虽然看似digits的数组长度看似由4变成3,其实只是numbersdigits指向同一个数组而已,而digits本身失去引用而变成垃圾,等待垃圾回收来回收(但其长度仍然为4),但其内部运行机制如下图所示。////////////图二,图三///////////
    因此当我们看一个数组时(或者其他引用变量),通常看成两部分:数组引用变量和数组元素本身,而数据元素是存放在堆内存中,只能通过数组引用变量来访问。从上述的示例中看出数组中存放的是基本类型,其实数组中还可以存放引用类型的。而存放基本类型的内存分布已经解释了,而存放引用类型的内存分布则相对复杂了。来看一段非常简单的程序。
public class TestPrimitiveArray {
   public static void main(String[] args) {
       //1.定义数组
       int[] numbers;
       //2.分配内存空间
       numbers = new int[4];
       //3.为数组元素指定值
       for(int i = 0;i < numbers.length;i++) {
           numbers = i * 10;
       }
    }
}
按以上步骤的内存分布示意图:///////////////图四//////////////////
从图中可看出数组元素直接存放在堆内存中,当操作数组元素时,实际上是操作基本类型的变量。接下来再看一段程序:
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();
       }
    }
}  
对于数组元素为引用类型在内存中的存储与基本类型不一样,此时数组元素仍然存放引用,指向另一块内存,在其中存放有效的数据。/////////图五///////////
图六  为多维数组的内存分配。
更多图片 小图 大图
组图打开中,请稍候......

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

1 个回复

倒序浏览
学习了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马