这里是一则小广告:

关注作者请点击这里哦:zdr0

我的专栏里面不仅有学习笔记,也有一些科普文章,相信我的专栏不会让您失望哦~大家可以关注一下:数学及自然科学

-尽力写最好的讲义,尽力写最好的科普。


文章总结自毕向东老师的Java教程。

数组概述以及数组的第一种定义格式

在一般的高级语言中,都具有数组这个概念。那什么是数组呢?根据字面意思理解,数组就是一组数据,而这些数据的类型的是一致的。也就是说数组是同一种类型的数据的集合。其实说白了数组就是一个容器。既然是容器,那就是一个实体,而且它可以用来装东西。数组这个容器就是用来装数据的,而且这些数据必须是同一种类型的。

做个比喻:我现在有一个筐,这个筐中装的都是橘子,所以,我不能把苹果或者别的什么放进这个筐中。因为要保证我这个筐中装的都是橘子。这个筐就是数组,橘子就是里面的数据。

当我们定义了一个数组之后,我们就可以避免同时面对一大堆数据了,而是面对一个整体。数组有一个很明显的优点,就是数组可以给它里面的元素从0开始编号,以方便操作这些数据。

首先,我们先来看一下再在Java中创建数组的第一种格式:

class 

我们来简单说明一些这个格式。如果要在内存中建立一个数组的话必须有区别于其他内容(比如声明变量),所以,我们需要一个关键字来建立这样一个可以存储很多数据的实体,这个关键字就是

。这里的
可以理解为“新建”。
了之后就说明需要一个空间,这个空间中要存储很多数据,那么要存什么类型的数据呀?这时候就要在
后面加上我们要存储的数据类型了,那么这些数据要存在哪里呢?要存在数组[]这个容器中

容器有很多种,数组只是其中一种。

这里的[]可以理解为数组这种容器的“形状”。我们要在这个数组中存在多少个数据呢?这就需要定义数组的长度了,

一旦创建数组,就要同时明确它的长度!换句话说,我们必须要明确容器的size。

显然,数组的长度就是数组中元素的个数。比如,我要建立一个可以存放

类型的数据的容器,这个容器中要存放3个整数,那么我们可以这样写:
new 

这就是定义数组的一种格式的右半部分。但这样建立了数组之后我们并不能使用它,因为它还缺少一个名字呀!这就像人一样,如果一个人连名字都没有的话那如何才能让他去干活呢?总不能叫喂喂喂吧,很没礼貌的...所以,数组也像我们人一样,也需要一个名字,这样才能对其进行其他操作。新建立的数组就像一个刚出生的婴儿,所以它的名字就需要我们来起啦。但是在起名字的时候一般我们都要明确类型,比如我们在声明变量并赋初值的时候,

int 

我们同时明确了变量

的数据类型是
。所以,我们在给数组起名字的时候也要明确类型,这里的类型就是数组中存储的元素的数据类型。但是如果,我们在给数组起名的时候,写成了:
int 

的话那就废了,因为左边声明的是一个变量,而变量只能用来存储数据,怎么可能来存储一个实体呢?所以,我要这样写:

int

这样,我们在给数组起名为arr 的同时明确了arr是数组类型(不要忘了[]是数组这个容器的“形状”呀!),并且明确了这个数组中装的都是

类型的数据。

01这句代码读作:

创建了一个

类型的数组,并将该数组命名为arr,右边通过
关键字创建了一个数组实体,这实体中元素的数据类型是
,并可以存放3个
类型的数据。

int 就说明我这个筐中只能用来装橘子,不能用来装别的!

01中的代码相当于说我有一个叫arr的筐,然后我把这个筐隔成三个格子([3]),而且我规定这个筐中只能装橘子(

),尽管目前这个筐中什么也没装。

那么现在我们来尝试操作一些这个筐好了。现在,我想打印这个数组中的第一个元素,那么我们可以这样做:

class 

我们可以直接打印

,因为我们在文章开头说过:数组有一个很明显的优点,就是数组可以给它里面的元素从0开始编号。所以一个数据的编号就为0,这个编号的术语叫做

索引

哎,等一下!刚才不是说这个筐是空的吗?那我们打印第一个元素会得到什么呢?JVM给出的答案是0。这就奇怪了,那我再打印

注意,这个数组是没有3号索引的!因为长度为3的数组里面的元素编号只能是0,1,2。一般来讲,对于一个长度为n 的数组,最后一个元素的编号是n-1。

试试好了,结果发现打印的结果依然是0。这是为啥呢?先不着急,在后面的堆内存中我们会说明原因。

如果我们想在这个筐中的某个格子里放进橘子(比如给编号为0的位置赋值为1),那么我们就可以这样做:

arr

这种操作类似于给变量赋值。

内存空间的划分

Java程序运行的时候要在内存中开辟空间,因为内存的运算速度比较快。其实任何一款软件在运行的时候都会在内存中开辟空间,比如chrom,wechat等等...所以,JVM(Java 虚拟机)在运行的时候也需要在内存中开辟空间。如图片2.1所示:

图片2.1:内存划分。

JVM还会对自己所属的内存空间进行进一步的划分。仍如图片2.1所示。可是为什么JVM还要对自己所属的空间做进一步的划分呢?我们再来做个比喻吧:

超市,超市中的不同区域售卖不同的物品,比如有个区域买水果和蔬菜,有的区域卖海鲜和肉类,还有的区域卖酒水,等等...这样做的原因除了方便顾客之外还便于管理。总不能说开一家超市,然后把所有东西都摆在一起卖吧?鞋和肉一起卖不合适吧...

所以,区域的划分一方面是为了秩序。JVM也是同理,每一片内存,自身内部的数据的处理方式都不同。那么JVM里面的空间具体被划分为几片呢?答案是5片,它们分别是:

  1. 寄存器
  2. 本地方法区
  3. 方法区
  4. 栈内存
  5. 堆内存

它们之间是有顺序的。下面,我们先来主要学习一下栈内存和堆内存。

栈内存

对于栈内存,我们需要明确的是里面都存了什么。(在超市中,这一块是卖啥的)

在栈内存中存储的都是局部变量。那什么是局部变量呢?局部变量通常是定义在方法中的变量。而且,变量的作用域一旦结束,该变量在内存中就自动释放。这就意味着栈内存的更新速度比较快,因为在栈内存中,变量的生命周期比较短。

一般来讲,局部变零都有自己的所属函数,函数在被加载进栈内存的同时,其中的局部变量也被加载进栈内存。那么除了函数以外哪里还有局部变量呢?比如在

循环中:
class 

循环变量

就是一个局部变量,当
循环结束后,变量
在内存中就被释放了。所以,不能在
循环外操作变量
。除了
循环中有局部变量以外,
代码块中也有局部变量:
class 

还有一个地方也有局部变量,就是在局部代码块中:

class 

局部代码块看似毫无用途,但是在大程序中,或许会起到优化程序的作用。比如,我们有一个变量,而对这个变量的操作早早就结束了,而且将来再也不会操作这个变量了,那我们就可以将这个变量及其操作放在一对{}中,当这个{}结束时,里面的变量就被自动释放了,这样这个变量就不会在占用内存了。

堆内存

堆内存中存储的是数据和对象(数组就是对象)凡是通过

创建的,全部在堆内存中

。看一下堆内存的特点。我们先来画个图看看,我们画这句话:

int

在内存中的行为。首先,我们将JVM所属区域中的栈内存和堆内存的区域画出来。如图片4.1所示:

图片4.1:栈内存和堆内存。

首先,我们要明确的是

是在主函数中的,所以乡乲乲是一个局部变量,所以,它在栈内存中。而
是一个实体(实体的作用是用于封装多个数据),并且通过关键字
创建,所以它在堆内存中。在实体中,既然封装了多个数据,那么某个数据的消失不会影响其他数据的使用,所以实体不会消失。实体和局部变量的区别。

上例中的程序开始执行的时候是主函数先被加载进内存,而且进栈内存。可是为何主函数要进栈而不是堆呢?原因很简单,因为主函数里面的局部变量都要进栈,所以主函数要先进栈,主函数进栈之后,主函数里的局部变量也就进栈了。如图片4.2所示:

图片4.2:主函数进栈。

创建变量是右侧赋给左侧,但这里右边不是一个具体值,而是一个实体,所以,这时堆内存就出现了。使用

关键字会在堆内存中开辟一块空间,这个空间是由特点的。内存在存储数据的时候都是通过地址来体现的(也就是说任何数据在内存中都有地址),所谓的内存地址就是一串连续的二进制数,但是这个数字或许太长,所以,我们可以使用更大的进制数字进行表示。所以这个实体就被分配了一个地址,我们就使用16进制来表示这个地址(地址瞎编的)好了。如图片4.3所示。
图片4.3:在堆中分配空间并分配地址值。

地址分配完毕后,这样数组就被分配了一块空间了。而我们知道,数组中的元素都是由索引的,所以对于上例中长度为3的数组,我们可以将分配给数组的这一块空间分成三个格子,而且每个格子都有自己的编号。如图片4.4所示。

图片4.4

刚刚我们说过,在我们没有对数组赋值的情况下数组中的所有元素的值都是0。这是因为数组实体在堆内存中创建完毕后每一个空间都会完成一次默认初始化,这是堆内存的特点。需要注意的是,不同的数据类型默认初始化的值是不同的:

  • 整数类型的默认初始化值均为0;
  • 小数类型的默认初始化值为0,对于
    ,它的默认初始化值为0.0f;
  • 布尔类型的默认初始化值为false;
  • 字符类型的默认初始化值为'u0000'。u是Unicode码,后面的000代表了两个字节,作为了解即可。

所以,对内存的第一个特点是,每一个实体都具有一个地址值。第二个特点是,堆内存中的每一个变量都有一个默认初始化值,根据数据类型的不同而不同。现在的问题是我们如何将右侧的对象赋给左侧的局部变量呢?答案是将数组实体的地址值赋给

这个局部变量。当变量
获得了这个数组的地址值之后,它就指向这个数组。如图片4.5所示:
图片4.5

可以看出,这里与我们之前所学的基本数据类型是不一样的。基本数据类型是要把参与运算的数据存储在变量当中。所以,这种数据类型不在是基本数据类型,而是引用数据类型。所以,可以说是arr引用了堆内存中的一个实体。

在C++中,这个机制叫做指针

现在,如果我们要打印

,则需要输出语句
这时会现在栈内找到arr,然后通过地址找到arr在堆中所对应的数组,紧接着,在这个数组中找到索引为零的元素,然后就可以将这个元素打印出来了。当我们不想让引用数据类型指向任何实体时,我们可以使用关键字
比如
。所以,
的作用就是取消引用数据类型的指向。

当实体不被指向时,它在内存中就毫无用处了,但实体不会像在栈内存中的局部变量一样立刻被释放,而是被视为垃圾,这些垃圾是被自动回收的,因为有一个垃圾回收机制,它会检测堆内存中是否有垃圾,但何时回收这些垃圾却不一定。这就是堆内存的第三个特点。

内存图解练习

我们再来画两句话:

int

上述的代码不一定在主函数中,但它们自己的所属函数,所以,我们在栈内存中绘制一个矩形方框来代表上例代码的所属函数。如图片5.1所示:

图片5.1

首先,

被加载进栈内存,右侧
了一个数组,所以,内存要在堆中给该数组分配一块空间,并赋予地址值。如图片5.2所示。
图片5.2

然后,这一块被分配的区域将进一步划分为三个小的区域,么个小区域都有自己的索引。而且由于没有给数组x赋值,而数组x中的元素是

类型的数据,所以,x中所有元素的值均为0。之后,这个数组的地址值就会赋给
,然后x指向这个数组。如图片5.3所示。
图片5.3

这样

在内存中的行为就绘制结束了。对于
的绘制方法是一样的,下面我就直接画出结果了,大家可以尝试自己画一画。如图片5.4所示。
图片5.4

有同学会问了,既然右侧都是

那为何还要在堆内存中为乹重新分配空间啊?大家记住,只要有
,就要在堆中重新为实体分配空间。

下面的第三、四句话是分别为数组乸和数组乹中的索引为0的元素赋值,这两句话比较简单,所以我就画在一起了。如图片5.5所示。

图片5.5

可见,原来的0都被覆盖掉了。

下面我们继续添加代码:

int

这句话该如何绘制呢?因为乸和乹都是引用数据类型类型,所以,
就是将y的地址赋给x,然后x原来的地址就被覆盖掉,所以,x不再指向原来的实体,而是同y一样,是指向数组y。这样,数组x就在堆中称为了垃圾将来会被自动回收。如图片5.6所示。
图片5.6

这是如果在打印

,所打印的结果是2,而不是1!再加一句代码:
int

引用数据类型y的指向被取消了,请问这时候的数组y是垃圾吗?答案是 不是垃圾。因为引用数据类型x仍指向它。


java学习笔记_Java大白话学习笔记(01)—数组以及内存图解相关推荐

  1. java中二叉树_java后端学习路线

    "学习真的是一个循序渐进的过程,也是一件需要坚持的事情.对于这篇文章,不同阶段的人可能有不同的理解,所以我把我整理的比较全面的java学习路线分享给大家,以供参考.下面的这个学习路线主要针对 ...

  2. java 线程起名字_java多线程学习三::::为什么要给线程起名字并且知道守护作用?...

    为什么要会线程起名字呢? 你如果拿到一连串的Thread-01,Thead-02我想你应该会疯掉,看以下代码 package rs.thread.day0504; /** * @auther rs * ...

  3. java新人培训_Java新人学习必要的步骤以及全套学习路线!

    原标题:Java新人学习必要的步骤以及全套学习路线! 想学Java,刚开始有没有觉得无从下手呢?其实Java的基础知识点,并不多,但是一定要吃透,因为这是为后续核心的学习打下一个良好的基础.简单来说, ...

  4. 程序员基本功01数组与内存控制

    以下的答案为我自己的读书心得(捏造的答案),如有童鞋不忍直视,还请不吝赐教 1.JAVA数组基本语法 int[] a 2.JAVA数组的静态特性 当数组被初始化后,数组的长度是不可改变的 3.JAVA ...

  5. java读书雷_Java多态学习笔记

    java多态学习笔记 概述 多态的格式与使用 /* 代码中体现多态性:父类引用指向子类对象. */ 格式: 父类名称 对象名 = new 子类名称(); 或者 接口名称 对象名 = new 实现类名称 ...

  6. core java 9 代码_Java Core 学习笔记——3.char/Unicode/代码点/代码单元

    通用字符集(UCS) UCS是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所制定的标准字符集. UCS包括了其他所有的字符集(包含了已知语言的所以字符). ISO/IEC 1 ...

  7. java冰法_Java基础学习笔记二 Java基础语法

    注释 注释用来解释和说明程序的文字,注释是不会被执行的. 单行注释 //这是一条单行注释 public int i; 多行注释 /*这是 * 一段注释, * 它跨越了多个行*/ public void ...

  8. java语言程序设计 笔记_Java语言程序设计笔记

    本文主要向大家介绍了Java语言程序设计笔记,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 对象的自动清除 · 对象回收是由垃圾回收线程负责 · System.gc()方法可以要求系 ...

  9. 格力电器Java面试题_JAVA设计模式学习--工厂模式

    今天谈一下对工厂模式学习的总结. 看完视频和文章之后要自己表述工厂模式,总是感觉无从说起,不知道怎么去定义工厂模式,反复看了几遍之后终于理解一点. 自己理解工厂模式是通过这两种模式的特点来理解和定义的 ...

  10. java 方法泛型_Java基础学习,什么是泛型概念,使用泛型有哪些好处?

    一般的类和方法,只能使用具体的类型,要么是基础数据类型,要么是自定义类. 如果要编写可以应用与多种类型的代码,这种刻板的限制对代码的束缚就会很大. 泛型的字面概念: 适合用于许多类型. 在面向对象中, ...

最新文章

  1. java培训班如何选择
  2. 新看了两件家具请朋友们给点意见
  3. Aspx页面中直接编写javascript脚本
  4. PHP判断是否有Get参数的方法
  5. Linux bond6配置文件,Linux服务器网卡绑定bond配置(示例代码)
  6. GPU Pro2 - 3.Procedural Content Generation on the GPU
  7. ListableBeanFactory接口
  8. 再见Jenkins,从Gitlab代码提交到k8s服务持续交付只需七毛三
  9. Kong Api 初体验、Kong安装教程
  10. os是android5.0,Funtouch OS 2.1曝光 完美改Android5.0
  11. TCP TIME_WAIT 详解
  12. fastjson反序列化漏洞_【安全风险通告】fastjson反序列化远程代码执行漏洞安全风险通告...
  13. SQL Server 2008将数据导出到SQL脚本文件
  14. 四格漫画《MUXing》——请客记
  15. Spring Boot的每个模块包详解
  16. 数据结构——>单向环形链表
  17. 在linux下运行.o文件,Linux环境下在可执行程序中嵌入资源文件
  18. 《 没有业绩怎么写好年终总结.ppt 》
  19. python包导入细节
  20. 泛微OA二次开发环境搭建 ecology二次开发

热门文章

  1. 我亦云云——也谈云计算(3)
  2. maven配置私服信息
  3. can not find Artifact XXX 的原因
  4. Oracle中将小数转换成字符丢零.截取小数.除数为零解决法
  5. Salty Fish(区间和)
  6. 从B树、B+树、B*树谈到R树
  7. java类加载器和父类委托机制
  8. cisco5525防火墙***流量分离即***和nat并存的配置方式
  9. IS技术:稳定压倒一切
  10. IT人母亲的美国之行(3)