Java 基础【04】数组内存分配
可能Java 数组大家都很熟悉,最近我遇到了一个关于Java 数组内存分配的问题。
突然发现许多书上“基本数据类型存储在栈内存当中,对象则保存在堆内存”这句话完全是错误的。下面是个简单的例子代码:

public class Test {
public static void main(String[] argv) {
// 静态初始化数组
String[] names = { "Michael", "Orson", "Andrew" };
// 动态初始化数组
String[] animal = new String[4];
// 让animal 指向 namens 数组所引用的数组
names = animal; System.out.println(names.length);
System.out.println(animal.length);
}
}

“Java 数组大小是不能改变的”这可能大家都听过,那上面这段代码就有问题了。
animal [] 长度为4,而names [] 数组的长度只有3,但是经过一个赋值语句,两个数组的大小就都变为4了。
这不是改变了数组的大小吗?
好吧,问问技术前辈吧,对数组的存储方式有了全新的认识。
下面是我的一点理解:(如果有错误的,刚好被大神你看到了,也请你能够指出来。)
上面的的 names 和 animal 不代表这个数组对象,仅仅是数组的变量而已,和C里面的指针是一样的,这样的变量叫做引用变量。
数组对象是保存在堆内存当中,大小当然是不能改变的,但是数组变量却能够指向其他的数组对象,可以看看下面这个图:
蓝虚线是赋值语句 names = animal; 之前 names 和 animal 数组变量指向的堆内存当中数组对象;
红线是是赋值语句 names = animal;之后 names 和 animal 数组变量都同时指向一个数组对象。当然这时候 Java 垃圾回收机制这时候就会发现那个没人引用的数组对象然后把它带走。
从上面还可以看到,“Michael”,"Orson","Andrew" 这些都是基本的数据类型吧。但是他们却存储在堆内存当中。
实际上应该这样说:局部变量放在栈内存当中,(像上面的 names[],animal[] 这种引用类型的变量,还有一些基本类型的变量),但应用变量所引用的对象是保存是堆内存当中的。(包括数组还有一些我们平常写的普通的类对象)
Java在堆内存当中的对象通常是不允许直接访问的,但你可以想到直接访问的后果。为了访问堆内存当中的对象,这时候就需要引用变量这个中介。
什么时候Java存储在栈内存中的变量是仅仅是引用变量? 什么时候它又换了身份变为货真价实的JAVA对象纳?嗯,看看下面这个例子:

public class Animal {
private String name;
private int age; Animal(String name, int age) {
this.name = name;
this.age = age;
} public void info() {
System.out.println(name + " " + age);
}
}
public class Test { public static void main(String[] argv) {
// 动态初始化数组
Animal[] animal = new Animal[2];
Animal cat = new Animal("cat", 1);
Animal dog = new Animal("dog", 2);
animal[0] = dog;
animal[1] = cat; // 当数组变量引用对象的方法(或者属性)的时候,它就变为实际的Java 对象
System.out.println(animal.length);
//dog 这个原本存储在栈内存当中的对象引用通过调用对象的方法变为实际的对象
dog.info();
animal[0].info();
}
}

只有当栈内存中的引用变量调用了对象的方法或者是指向了对象的属性的时候,它就从变量真正成了对象了。
(比如上面例子中的 cat,dog 对象引用变量,animal[]数组变量)。 通过
animal[0] = dog;
animal[1] = cat;
使得两个变量都指向了存储在堆内存当中的对象,所以他们俩个打印出来的信息是一模一样的。
上图中蓝线是赋值语句:
animal[0] = dog; animal[1] = cat;
之前的变量指向的状态,红虚线是赋值语句之后的状态,animal[0]和dog ,animal[1] 和cat 所指向的都是相同的堆内存空间。
(PS:我还是要感谢这几个月来那几个面试官对我从头到尾的虐,虽然现在实习的事情还没有个准信,当我发现我要走的路还很长很长)
Java 基础【04】数组内存分配的更多相关文章
- java中二维数组内存分配
区分三种初始化方式: 格式一: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的元素有多少个. //例:int arr[] ...
- Java基础-对象的内存分配与初始化(一定要明白的干货)
首先,什么是类的加载?类的加载由类加载器执行.该步骤将查找字节码(classpath指定目录),并从这些字节码中创建一个Class对象.Java虚拟机为每种类型管理一个独一无二的Class对象.也就是 ...
- 13.Java基础_数组内存图
单个数组内存图 new int[3]: 在堆内存里申请一块空间存储int类型的变量(初始化时值都为0) int[] array: 在栈内存申请一块内存存储堆内存里数组的首地址 array[i]: 通过 ...
- java 数组声明定义 数组内存分配 数组初始化 数组引用 数组的遍历
一,数组的定义 Java 中定义数组的语法有两种: 1. type arrayName[]; 2. type[] arrayName;type 为Java中的任意数据类型,包括基本类型和组合类型,ar ...
- java程序运行时内存分配详解
java程序运行时内存分配详解 这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下 一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个 ...
- Java进阶2 数组内存和对象的内存管理知识
Java进阶2 数组内存和对象的内存管理知识 20131028 前言: 在面试的时候,如果是Java的编程语言,也许你认为没有什么可以问的,只能够说明你对于Java了解的太浅了,几乎就是两个星期的节奏 ...
- 《深入理解 java 虚拟机》学习 -- 内存分配
<深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...
- [转]使用Java Mission Control进行内存分配分析
jdk7u40自带了一个非常好用的工具,就是Java Mission Control.JRockit Misson Control用户应该会对mission control的很多功能十分熟悉,JRoc ...
- java 基础概念 -- 数组与内存控制
问题1: Java在声明数组的过程中,是怎样分配内存的? 在栈内存中 建一个数组变量,再在堆内存中 建一个 数组对象.至于详细的内存分配细节,还得看 该初始化是 数组动态初始化 还是 数组静态初始化. ...
随机推荐
- AOP面向切面编程笔记
1.AOP概念:Aspect Oriented Programming 面向切面编程 2.作用:本质上来说是一种简化代码的方式 继承机制 封装方法 动态代理 …… 3.情景举例 ①数学计算器接口[Ma ...
- poj-1011 sticks(搜索题)
George took sticks of the same length and cut them randomly until all parts became at most 50 units ...
- cf 1006E
#include <iostream> #include <cstdio> #include <cstring> #include <string> # ...
- Spring核心技术(十三)——环境的抽象
本章将描述一下Spring中针对环境的抽象. Environment是一个集成到容器之中的特殊抽象,它针对应用的环境建立了两个关键的概念:profile和properties. profile是命名好 ...
- luogu2123 皇后游戏
好题. 网上看到的范围是:\(T \leq 10\),$ n \leq 50000$, $ a_i,b_i \leq 10^9$. 我们按照贪心惯常的思路考虑交换相邻的两个人.容易发现,对于相邻的两个 ...
- webpack 环境搭建+实现热更新
让我们一起构建一个小的app 为了便于你更好的了解Webpack带来的好处,我们将会构建一个非常小的app并将资源文件打包.在这个教程中我推荐基于Node4或Node5和NPM3来进行开发,这样就避免 ...
- 如何用字体在网页中画icon
一.用css雪碧图 1.简介 CSS Sprites在国内很多人叫css精灵,是一种网页图片应用处理方式.它允许将一个页面涉及到的所有零星图片都包含到一张大图中, 利用CSS的“background- ...
- Leetcode 450.删除二叉搜索树的节点
删除二叉搜索树的节点 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变.返回二叉搜索树(有可能被更新)的根节点的引用. 一般来 ...
- Python封装与隐藏
今日内容: 1.封装与隐藏2.property3.绑定方法与非绑定方法 知识点一:封装与隐藏 1.什么封装: 封:属性对外是隐藏的,但对内是开放的 装:申请一个名称空间,往里装入一系列名字 ...
- 【转】javascript操作Select标记中options集合
先来看看options集合的这几个方法:options.add(option)方法向集合里添加一项option对象:options.remove(index)方法移除options集合中的指定项:op ...