1. Java数组是静态的

Java是静态语言,所以Java的数组也是静态的,即:数组被初始化后,长度不可变

静态初始化:显式指定每个数组元素的初始值,系统决定数组长度

String[] books = new String[]{"疯狂Java讲义","Thinking in Java","Java核心技术卷"};

String[] names = new String[]{"张三","李四","王五","赵六"};

动态初始化:显式指定数组的长度,系统决定每个数组元素的初始值

String[] strArr = new String[5];

以上两种初始化的内存使用情况如图所示:

动态初始化数组由系统决定每个数组元素的初始值,遵循以下规则:

byte、short、int、long类型的数组的初始值为0

float、double类型的数组的初始值为0.0

char类型的数组的初始值为'\u0000',表现为空字符'',但要占位

boolean类型的数组的初始值为false

引用类型的数组的初始值为null

一旦数组初始化完成,则长度不可改变,以下代码造成了数组初始化后长度可改变的假象:

books = names;

strArr = books;

System.out.println(books.length); // 4

System.out.println(strArr.length); // 4

Java的数组变量是一种引用类型的变量,数组变量并不是数组本身,它只是指向堆内存中的数组对象,改变一个数组变量所引用的数组,可以造成数组长度可变的假象。

上述代码让books数组变量和strArr数组变量都指向了names数组变量引用的数组,这样做的结果就是让三个数组变量都引用了相同的数组对象。内存图如下:

而原来strArr和books引用的数组对象的长度不会改变,由于已经没有变量引用它们,它们成为垃圾,等待垃圾回收机制来回收。此时,程序使用strArr、books、和names这三个变量时,将会访问同一个数组对象。

JavaScript是动态语言,其数组的长度可以改变:

var arr = [];

document.write("arr的长度为:" + arr.length + "
"); // 0

arr[0] = 1;

document.write("arr的长度为:" + arr.length); // 1

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

实际上,懂得了Java数组的内存机制后,我们可以说:数组不是必须初始化,或者说,数组初始化不仅有之前介绍的两种方法,可以完全换一种方法:

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

int[] arr;

arr = nums;

对于数组对象来说,必须初始化,也就是为该数组对象分配一块连续的内存空间,连续内存空间的长度就是数组对象的长度。

对于数组变量来说,不需要进行初始化,只需让其指向一个有效的数组对象就可以。

实际上,所有引用类型的变量,其变量本身不需要任何初始化,需要初始化的是它所引用的对象。

3. 基本类型数组的初始化

程序直接先为数组分配内存空间,再将数组元素的值存入对应的内存中。

int nums; ①

System.out.println(nums); ②

nums = new int[]{1, 2, 3, 4}; ③

System.out.println(nums.length); ④

我们来分析①-④步的内存:

① 定义nums数组变量后的存储示意图如下:

对于②行代码来说没有任何问题,虽然nums变量并未引用到有效的数组对象,但此时并未通过nums变量访问数组对象的方法或属性,所以没有问题。

③ 静态初始化nums数组后的存储示意图如下:

对于④行代码来说,此时访问了nums数组对象的属性,所以要求nums必须引用一个有效的对象。

当通过引用变量来访问实例属性或者调用非静态方法时,如果该引用变量还未指向有效的对象,程序就会抛出运行时异常:NullPointerException,例如,第二行代码如果为:

System.out.println(nums.length);

就会抛出NullPointerException

误区:基本类型的数据的值存储在栈内存中

实际上,应该是所有的局部变量都保存在栈内存中,不管是基本类型还是引用类型,局部变量都保存在各自的方法栈中。

4. 引用类型数组的初始化

引用类型数组的数组元素仍然是引用类型,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象,包括数组和Java对象。

下面程序的执行代表了引用类型数组初始化的典型过程:

class Person{

String name;

int age;

public void info(){

System.out.println("name:" + name + ", age:" + age);

}

}

// 创建两个Person对象

Person p1 = new Person();

p1.name = "张三";

p1.age = 20;

Person p2 = new Person();

p2.name = "李四";

p2.age = 30;

// 将两个Person对象赋给数组元素

person[0] = p1;

person[1] = p2;

// 结果一样,p1和person[0]指向同一个对象

p1.info();

person[0].info();

分析内存:

5. 数组元素就是变量

当数组引用变量指向一个有效的数组对象之后,程序就可以通过该数组变量访问数组对象。

Java语言不允许直接访问堆内存中的对象,因此无法直接访问堆内存中的数组对象,程序将通过数组引用变量来访问数组对象。

Java语言避免直接访问堆内存可以使程序更加健壮,如果程序直接访问并修改堆内存中的数据,可能破坏内存的数据完整性,从而导致程序Crash。

无论哪种类型的数组,其数组元素其实相当于一个普通变量。

下面程序师范了将数组元素和普通变量相互赋值的情形:

class Cat{

String name;

double height;

public Cat(String name, double height){

this.name = name;

this.height = height;

}

public void info(){

System.out.println("name:" + name + ", height:" + height);

}

}

public class TestArray {

public static void main(String[] args) {

int[] a = new int[5];

for(int i=0; i

a[i] = ++i;

}

int x = a[0];

int y = 99;

a[4] = 99;

Cat[] cats = new Cat[2];

cats[0] = new Cat("咪咪", 10.0);

cats[1] = new Cat("卡卡", 12.2);

Cat c1 = cats[0];

Cat c2 = new Cat("豆豆", 11.1);

cats[1] = c2;

}

}

内存分析:

6. 没有多维数组

所谓多维数组,其实只是数组元素元素依然是数组的数组,1维数组的数组元素的基本类型或者引用类型,2维数组的数组元素是1维数组,3维数组的数组元素是2维数组...N维数组的数组元素是N-1维数组。

Java允许将多维数组当成1维数组来处理,初始化多维数组时可以先初始化最左边的维数,此时该数组的每个数组元素都相当于一个数组引用变量,这些数组还需要进一步初始化。

如下程序示范了多维数组的用法:

public static void main(String[] args) {

int[][] a;

a = new int[4][];

// 把a当成一维数组,遍历a数组的每个数组元素

for(int i=0; i

System.out.println(a[i]); // 输出都为null

}

a[0] = new int[2];

a[0][1] = 2;

for(int i=0; i

System.out.println(a[0][i]); // 输出0和2

}

}

内存分析:

说明:一般我们认为通过数组的length属性可以获取数组的长度,其实这个说法不够准确,例如数组a,它是一个传统的“二维数组”,它的长度好像定义不是很明确,其实,数组的长度指的是数组所分配的连续内存空间的长度,所以说a数组的长度为4.

我们用一个“极端”的程序来更好的理解数组在内存中的分配机制:

public static void main(String[] args) {

Object[] objArr1 = new Object[3];

objArr1[1] = new Object[2];

Object[] objArr2 = (Object[]) objArr1[1];

objArr2[1] = new Object[3];

Object[] objArr3 = (Object[]) objArr2[1];

objArr3[1] = new int[5];

int[] iArr = (int[]) objArr3[1];

for(int i=0; i

iArr[i] = ++i;

}

}

内存分析:

此时的objArr1不再是一个简单的一维数组,它是一个四维数组。

最后我们执行如下语句:

System.out.println(((int[])((Object[])((Object[])objArr1[1])[1])[1])[2]);

通过以上内存分析不难得出结果为3.

通过上面的分析不难得出,多维数组的本质仍然是一维数组。

因为Java是强类型语言,所以上诉代码需要多次强制类型转化,如果用弱类型语言实现会简单很多,比如用JavaScript实现:

var objArr1 = [];

objArr1[1] = [];

var objArr2 = objArr1[1];

objArr2[1] = [];

var objArr3 = objArr2[1];

objArr3[1] = [];

var iArr = objArr3[1];

for(var i=0; i<5; i++){

iArr[i] = i;

}

document.write(objArr1[1][1][1][2]);

java 数组 内存_图解Java数组的内存分配相关推荐

  1. java简单数据结构_图解Java常用数据结构

    最近在整理数据结构方面的知识, 系统化看了下 Java 中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于 jdk8, 可能会有些特性与 jdk7 之前不相同, 例如 LinkedList ...

  2. java array缓存_有java数组

    [JAVA零基础入门系列]Day10 Java中的数组 [JAVA零基础入门系列](已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 D ...

  3. 读入的字节都写入字节数组中_使用Java将文件读入字节数组的7个示例

    读入的字节都写入字节数组中 嗨,大家好,Java程序员经常在现实世界中遇到编程问题,他们需要将文件中的数据加载到字节数组中,该文件可以是文本文件或二进制文件. 一个示例是将文件的内容转换为String ...

  4. java数组 初始化_用Java初始化数组

    java数组 初始化 具有使用C或FORTRAN等语言进行编程的经验的人熟悉数组的概念. 它们基本上是一个连续的内存块,每个位置都是某种类型:整数,浮点数或您所拥有的. Java中的情况与此类似,但有 ...

  5. java 将字符串数组清空_在Java中如何将字符串集转换为字符串数组

    详细内容 在Java中将字符串集(Set)转换为字符串数组(String[])的方法有:使用for循环,使用Set.toArray()方法,使用Arrays.copyOf()方法等等.下面我们就来具体 ...

  6. java数组乱码_关于Java乱码

    乱码本质:读取二进制时采用的编码与最初将字符转成二进制时的编码不一致. 编码(获得二进制数组的过程)时不抛出异常,数据就不会被破坏. Java关于乱码(MessyCode)问题 Java使用的是Uni ...

  7. java数组规定长度_为什么Java数组固定长度?

    正如其他答案所指出的那样,固定大小是定义的一部分,你必须与原作者交谈才能找到真相. 但是作为一般观点,实现可变长度容器要复杂得多,并且有很多策略可以实现它(链表,内存重新分配-). 如果作者在20世纪 ...

  8. java字符串数组排序_在Java中对字符串数组进行排序

    允许用户使用字符串数组.他们可以向数组添加字符串,从数组中删除字符串,搜索数组中的字符串,最终他们将能够对数组进行排序.分类是搞砸我的原因.我尝试过几种不同的方法.第一种方法是将数组转换为ArrayL ...

  9. java语言中类定义数组赋值_在Java语言中,下列对于字符数组的定义并赋值正确的是(选一项)_学小易找答案...

    [单选题]<茶花女--饮酒歌>这段音乐属于级进还是跳进的旋律? <茶花女-饮酒歌>.mp4 [简答题] [单选题]对外汉语教学中以系统讲授语言知识的一类课型,包括语音.词汇.语 ...

最新文章

  1. 不存在从void转换到sqlist的适当构造函数_拷贝构造函数与赋值构造函数
  2. 5G服务可以解决的4个企业WAN挑战 - vecloud
  3. 区别CALL SCREEN/SET SCREEN/LEAVE TO SCREEN
  4. mysql抓包_mysql抓包工具
  5. 如何看待事理图谱版magi--学迹
  6. matlab设计模拟高通滤波器
  7. 手机能上wifi电脑不行_电脑如何当Wifi供手机使用
  8. 2021年Java爬虫技术教程(一小时实现)
  9. wincc嵌入式excel报表 该报表系统能够读取WINCC中历史归档数据,产生出EXCEL报表文件,同时在画面中EXCEL控件实时显示
  10. 不定式和分词作状语的区别
  11. 搜狗推送接口之搜狗秒收录技巧分享
  12. mysql插入微信名称中的特殊字符
  13. 教你年入100万,互联网赚钱三板斧!
  14. 阿里云如何购买mysql_如何选购配置阿里云数据库RDS MySQL的流程 新手必看
  15. Web漏洞-Xss跨站
  16. 暗影精灵4风扇转速调节_答疑解惑,暗影精灵4用了半年的真实感受
  17. “逻辑和”与 “逻辑或”运算符
  18. 爬取沪深股票并找出最近1个月创出新高的股票
  19. 深度学习模型训练和关键参数调优详解
  20. 报:类com.qin.servlet.HelloServlet不是Servlet

热门文章

  1. 多节锂电串联保护板ic_如何有效保护锂电池板,一款优质的MOS管就能解决
  2. 【渝粤教育】国家开放大学2018年春季 0269-21T文学概论 参考试题
  3. 【渝粤教育】广东开放大学 房屋建筑学 形成性考核 (50)
  4. 使用计算机时 开关机顺序会,电脑如何正确开关机
  5. 多媒体计算机属于哪种教学,多媒体计算机属于哪种教学媒体(???)。
  6. 一建机电实务教材电子版_必背!一建《机电实务》高频考点,每日一背
  7. 【MFC系列-第9天】MFC消息映射机制的原理
  8. 第12秒做视频封面:阿里云视频截帧功能
  9. Python类与对象实验
  10. (Oracle)DDL及其数据泵导入导出(impdp/expdp)