Java进阶——数组与内存控制
下面将会深入探讨Java数组的静态特征。使用Java数组前必须对数组进行初始化,初始化的过程即给数组的所有元素都分配合适的内存空间,并指定初始值的过程。数组初始化以后将不能重新改变数组对象在内存中的位置和大小。从用法角度看,数组元素相当于普通变量,程序既可以吧数组的值赋给普通变量,也可以把普通变量的值赋给数组元素。但其实质是对内存中数组元素对象的操作。
1、数组初始化
Java语言是典型的静态语言,所以Java的数组也是静态的。Java中的数组必须经初始化后才可以使用,初始化即为数组对象的所有元素分配一个连续的内存空间,并为每个元素指定初始值。数组的初始化有两种方式:
>静态初始化:由程序员显式地指定每个数组元素的初始值,由系统决定数组的长度;
>动态初始化:程序员只指定数组长度,由系统为数组元素分配初始值。
下面是两种初始化方式的实例:
public class test01 {
public static void main(String[] args) {
//静态初始化数组
String[] str0 = new String[]{"小武灵灵" , "41009160"};
//静态初始化的简化形式
String[] str1 = {"小武灵灵" , "41009160"};
//动态初始化
String[] str2 = new String[2];
}
}
Java语言的数组变量是引用类型的变量,上面的三个数组变量按照声明的前后顺序(注意这里不是初始化的先后顺序)存储在main栈区中,其引用的数组是按照数组元素的顺序分别在堆内存中分配到长度为2的连续空间。
注意,虽然这里str0和str1变量引用的数组内容相同,但是绝不是同一个数组,也就是说内存中除了str2外,还有两个长度内容都相同的数组。
注意,鼎泰初始化和动态初始化不能同时使用。
而执行动态初始化时,程序员指定了数组的长度,即为每个数组元素指定所需的内存空间,系统负责为这些数组元素分配初始值。系统将按照如下规则分配到初始值:
>基本类型:
>整数类型(byte , short , int , long):数组元素的初始值为0;
>浮点类型(float , double):0.0;
>字符类型(char , string):’\u000’;
>布尔型(boolean):false;
>引用类型(类、接口和数组):null
1)、数组变量和数组对象
Java的数组变量是一种引用类型的变量,通常情况下被存放在栈内存中,它并不是数组本身,它只是指向堆内存中的数组对象(跟C语言里的指针差不多)。
数组对象是保存在堆内存中的连续内存空间。
理解了这两个概念之后,我们可以对数组的初始化有一个更深的认识,即对数组执行初始化,其实并不是对数组变量执行初始化,而是要对数组对象执行初始化(即为该数组对象分配一块连续的内存空间)。
认识到这一点之后我们可以解释这样一种假象,即认为数组的长度是可变的,例如下面的实例:
public class test01 {
public static void main(String[] args) {
String[] str0 = new String[]{"小武灵灵" , "41009160" , "陕西师范大学"};
String[] str1 = new String[2];
str1 = str0;
System.out.println("str1的长度为:" + str0.length);
}
}
相信大家可以自行解释这种假象,这里我就不解释啦!
2)、基本类型数组的初始化
基本类型数组的初始化过程为:程序直接为数组分配内存空间,再将数组元素的值存入对应的内存里。例如下面的代码块:
String[] str;
str = new String[]{“小武灵灵”
, “41009160”, “地信1班”};
注意,所有局部变量都是放在栈内存里保存的,不管其是基本类型的变量,还是引用类型的变量,都是存储在各自的方法栈区中;但引用类型变量所引用的变量(包括数组、普通Java对象)则总是存储在对内存中。
注意,引用变量本质上只是一个指针,只要程序通过引用变量访问属性,或通过引用变量来调用方法,该引用变量将会由它所引用的对象代替。
3)、引用类型数组的初始化
引用类型数组的数组元素依然是引用类型的,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象。例如:
class Student {
public String name;
public int number;
public void output() {
System.out.println(name + “,”+number);
}
}
public class Main{
public static void main(String[] args) {
Student[] stu = new Student[2];
System.out.println(“数组长度:” + stu.length);
Student xiaowu = new Student();
xiaowu.name = “小武”;
xiaowu.number = “41009160”;
stu[0] = xiaowu;
//下面两行代码所输出的结果都是一样的
stu[0].output();
xiaowu.output();
}
}
在上面的程序中,内存是这样分配的:首先引用数组变量stu[]初始化完成后,内存中开辟出了长度为二的空间用来存储student对象;对引用变量xiaowu初始化完成后,内存中开辟了出了能够存储一个student对象长度的空间,用来存储student对象;将xiaowu赋给stu[0],则在内存中数组stu[0]指向对象xiaowu。
2、数组的使用
当数组引用变量指向一个有效的数组对象之后,程序就可以通过该数组引用变量来访问数组对象。Java语言不允许直接访问对内存中的数据,因此无法直接访问堆内存中的数组对象,程序将通过数组引用变量来访问数据。
要对数组有一个更深刻的认识,需要理解两个关系:数组元素与变量间的关系、多维数组与变量间的关系。
1)、数组元素与变量间的关系
只要在已有数据类型之后增加括号,就会产生一个新的数组类型,例如:
>int à int[]:在int类型后增加[]即变为int[]数组类型
>Stirng à String[]:在String类型后增加[]即变为String[]数组类型
当程序需要多个类型相同的变量来保存程序状态时,可以考虑使用数组来保存这些变量。当一个数组初始化完成,就相当于定义了多个类型相同的变量。
无论哪种类型的数组,其数组元素其实相当于一个普通变量,把数组类型之后的括号去掉之后得到的类型就是该数组元素的类型。
从这个角度讲,数组元素就是变量。
注意,这里的数组元素并不是指数组对象中的数组元素,而是指数组变量的数组变量元素。
注意,main方法声明的变量都属于局部变量,因此它们都被保存在main方法栈中;但数组元素则作为数组对象的一部分,总是保存在堆内存中,不管它们是基本类型的数组元素,还是引用类型的数组元素。
2)、多维数组与变量间的关系
理解了数组元素与变量之间关系之后,如果已有的类型是int,在其后增加[]后得到一个数组类型;以int[]类型为已有类型,在其后增加[]后得到int[][]依然是数组类型;
以int[][]类型为已有类型,在其后增加[]后得到int[][][]依然是数组类型。
从上面可以看出,所谓多维数组,其实就是数组元素依然是数组的1维数组,2维数组是数组元素是1维数组的数组,3维数组是数组元素是2维数组的数组,4维数组是数组元素是3维数组的数组……N维数组是数组元素是N-1维数组的数组。
所以,实际上我们可以这样认为:没有多维数组,只有基本数据类型和引用数据类型。
综上,数组的初始化有静态初始化和动态初始化两种;数组对象和数组变量不是同一个概念对于数组变量而言;数组元素的类型分为基本类型的数组和引用类型的数组;所有局部变量都是存放在栈内存里保存的,但引用类型变量所引用的对象则总是存储在堆内存中;一定要区分它何时只是数组变量,何时代表数组对象本身;数组元素就是变量,没有多维数组。
分享到:
相关推荐
数组是一种引用数据类型,在内存中存储示意图如下: 1. 数组是一组数据的集合 2. 数组作为一种引用类型 3. 数组元素的类型可以是基本类型,也可以是引用类型,但同一个数组只能是同一种类型 4. 数组作为对象,...
第三部分 进阶: C,C++代码阅读与控制 201 第9章 语法与初级标准库 202 9.1 C++的基于过程设计 203 9.2 C++的基于对象设计: 模板与设计 203 9.3 面向对象设计 204 9.4 泛型开发与初级StdC库 204 第10章 数据逻辑与...
数组&链表进阶 栈 队列 算法思想 数论&枚举&递归&分治&回溯 排序及其源码实现 贪心&动态规划 高级数据结构 树论基础&二叉树 二叉搜索树&红黑树 BTree Trie树&赫夫曼树 堆树 图论基础 最短路径 高效查找算法 二分&...
本书是第II卷,以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,主要包括Java语法与面向对象技术、Java高级应用、窗体与控件应用、文件操作...
java基础1.1 输入输出用户交互Scanner用户交互Scanner进阶1.2 基本数据类型基本数据类型类型转换变量,常量,作用域运算符补充:包机制补充:JavaDoc1.3 顺序结构1.4 循环结构while循环do-while循环for循环增强型for...
2.1 版本控制与目录树的转换 2.2 表达目录树的差异 2.3 增量编辑器接口 2.4 但这是不是艺术? 2.5 像体育比赛一样的抽象 2.6 结论 第3章 我编写过的最漂亮代码 3.1 我编写过的最漂亮代码 3.2事倍功半 3.3 观点 3.4 ...
进阶: 内存限制10MB,但是只用找到一个没出现过的数即可。 常规方法:假设用哈希表来保存出现过的数,那么如果40亿个数都不同,则哈希表的记录数为40亿条,存一个32位整数需要4B,所以最差情况下需要40亿×4B = 160...
Go被称为“21世纪的C语言”,因其简洁的语法,以及自带的内存回收机制,使其可以拥有高速运行效率的同时,还能兼顾开发效率,所以越来越多大厂开始转投Go语言! 转行学习误区多 学习效率Down到底 在实际的开发...