随笔- 35  文章- 0  评论- 29 

关于Java 数组内存分配一点认识

 //总结:【

数组引用变量存储在栈内存中,数组对象存储在堆内存当中。
数组引用变量不需要初始化,数组对象要进行初始化。
而且在堆内存当中的数组大小是不能改变的。

可能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 当中数组是怎样存储的吗?”)
 
 
 

java内存基础(一)的更多相关文章

  1. java基础知识(四)java内存机制

    Java内存管理:深入Java内存区域 上面的文章对于java的内存管理机制讲的非常细致,在这里我们只是为了便于后面内容的理解,对java内存机制做一个简单的梳理. 程序计数器:当前线程所执行的字节码 ...

  2. java内存模型-基础

    基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间 ...

  3. Jvm基础(2)-Java内存模型

    Jvm基础(2)-Java内存模型 主内存和工作内存 Java内存模型包括主内存和工作内存两个部分:主内存用来存储线程之间的共享变量:而工作内存中存储每个线程的相关变量. 如下图所示: 需要注意的是: ...

  4. java基础(一):谈谈java内存管理与垃圾回收机制

    看了很多java内存管理的文章或者博客,写的要么笼统,要么划分的不正确,且很多文章都千篇一律.例如部分地方将jvm笼统的分为堆.栈.程序计数器,这么分太过于笼统,无法清晰的阐述java的内存管理模型: ...

  5. JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配

    Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和mu ...

  6. Java内存模型基础

    Java内存模型的基础 并发编程模型的两个关键问题 在并发编程种,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在 ...

  7. 《成神之路-基础篇》JVM——Java内存模型(已完结)

    Java内存模型 本文是<成神之路系列文章>的第一篇,主要是关于JVM的一些介绍. 持续更新中 Java内存模型 JVM内存结构 VS Java内存模型 VS Java对象模型(Holli ...

  8. 【java】java内存模型 (1)--基础

    并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信 ...

  9. Java基础学习总结(30)——Java 内存溢出问题总结

    Java中OutOfMemoryError(内存溢出)的三种情况及解决办法 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各 ...

随机推荐

  1. Ubuntu 1210怎么获得root权限登录

    Ubuntu 12.10 怎么用Root 登录?以下是Ubuntu 12.10 启用Root 登录的方法吗,希望对大家有些帮助吧! 方法如下: 1.先设定一个 Root 密码 sudo passwd ...

  2. redhat6.4 数据包无法到达

    由于redhat在初始化的时候,防火墙设置为icmp-host-prohibited,导致数据包无法到达. 具体iptables(所在目录/etc/sysconfig)如下: # Firewall c ...

  3. scjp考试准备 - 9 - 多态

    题目为如下代码的执行结果: abstract class Vehicle{ public int speed(){ return 0; } } class Car extends Vehicle{ p ...

  4. java.util.logging.Logger_01

    1.参考网址 1.1.java.util.logging.Logger使用详解 http://lavasoft.blog.51cto.com/62575/184492 1.2.Java内置Logger ...

  5. Treflection02_getMethods()_getMethod()

    1. package reflectionZ; import java.lang.reflect.Constructor; import java.lang.reflect.Method; impor ...

  6. HDU - 4746预处理莫比乌斯反演

    链接 求[1,n] 和 [1,m]中有多少对数的GCD的素因子个数小于等于p 直接暴力做特定超时,所以我们想办法预处理,对于p大于18(1到5e5的最大素数因子个数)的情况,每一对都满足条件,O(1) ...

  7. macOS 10.12 任何来源

    sudo spctl --master-disable 从旧系统升级过来的仍然会显示“任何来源”选项,全新安装的将不再显示这个选项.可以通过上面的命令重新显示出此选项,非必要建议不要修改.

  8. 三十六 Python分布式爬虫打造搜索引擎Scrapy精讲—利用开源的scrapy-redis编写分布式爬虫代码

    scrapy-redis是一个可以scrapy结合redis搭建分布式爬虫的开源模块 scrapy-redis的依赖 Python 2.7, 3.4 or 3.5,Python支持版本 Redis & ...

  9. Springboot项目打成war包,部署到tomcat上,正常启动访问报错404

    前言: 项目介绍,此项目是一个Maven多模块项目,模块项目:all(父模块):util (公用的工具类):dao(实体类.业务类.mapper.mapper.xml):business(业务serv ...

  10. CMD下修改mysql的root用户密码

    文章转载自... CMD下,切换到mysql的bin目录下(目录加入到环境变量中绕过此步) 输入 mysql -u root -p,输入旧密码,进入mysql状态 MySQL>use MySQL ...