各位前辈好,我是一个初学java的新手,最近学习内存部分内容遇到了如下问题,还望各位赐教。
1.是否所有基本类型数据都存储在栈上,那假如有这样一段语句??Point?p1?=?new?Point(1,?1);
传给其构造函数的1,1是int型,为什么他们存储在堆里。
?
2.在程序编译的时候,开始时是否只编译我运行的这个,有主函数的这个类,而其他的类(例如Point类)是不是不会被编译,在具体运行到该语句的时候再编译该类?
?
3.一个对象被创建时,会有额外的堆的开支来存储与这个对象的相关信息(比如方法之类的?)。我在网上看别人的文章时,有看到过“相同类实例化的对象只开辟一块空间来存储这些信息,而不是每个对象被创建时都会有这些额外开支”(我不确定是不是这样说,难道是说?被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支?)
?
4.如果我创建一个函数,这个函数需要被不断、大量重用,那么我是否应该尽力使传到该函数的参数为值类型(最好是byte、boolean),传递对象比传递值类型(如int)更占用内存么? ?因为我最近看视频才知道,传递一个对象的话,只是传递引用,那么不管传递多大的对象,传递的引用其大小不都是一样么,而且不用额外开辟储存空间存储这个引用,这样来说穿引用不是比传值类型更占优势?
?
5.程序在编译时,类里面的静态成员,常量就会被放到???静态、常量区,假如我在某个方法中有这样一段语句。Point?p1?=?new?Point(1,?1);???而我写的Point类中也有自己的静态与常量成员,那这些静态成员、常量也是被分配到静态、常量区存储么?是在程序一开始编译的时候存储,还是在创建第一个该对象时临时加进去?
?
6.对于ArrayList,它好像是顺序表,是否意味着它在堆上的存储是连续的?那当它自己初始化的容量不足,需要扩容时,他需要重新在堆开辟空间存储新元素,那么是否有可能ArrayList在堆上就不连续了,而是一块一块的分布,那这样不就与顺序表的概念相冲突了么?
------解决思路----------------------
1,
定义:在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;
堆内存用来存放由new创建的对象和数组以及对象的实例变量;
解释:
用Point p1 ;声明一个对象p1 时,将在栈内存为对象的引用变量p1 分配内存空间,但Point 的值为空,称p1是一个空对象。空对象不能使用,因为它还没有引用任何”实体”。
对象实例化时的内存模型,当执行p1=new Point(1, 1);时,会做两件事:在堆内存中为类的成员变量1,1初始化分配内存,最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量p1,以后就可以通过p1来引用堆内存中的对象了。
------解决思路----------------------
楼主是个好孩子。
我回答
第二题:编译的时候,会先编译所依赖的那些类B,如果B也依赖其他类,那么先编译B依赖的类,依次递归。
------解决思路----------------------
1.是否所有基本类型数据都存储在栈上,那假如有这样一段语句 Point p1 = new Point(1, 1);
传给其构造函数的1,1是int型,为什么他们存储在堆里。
===========================================================================
是否所有基本类型数据都存储在栈上:否;
p1是内存地址,如果 p1是成员变量保存在堆里,如果是局部变量,会保存在Java虚拟机栈的局部变量表;
2.在程序编译的时候,开始时是否只编译我运行的这个,有主函数的这个类,而其他的类(例如Point类)是不是不会被编译,在具体运行到该语句的时候再编译该类?
===============================================================================================
Java不是脚本语言,不会动态编译,但可以动态加载;
3.一个对象被创建时,会有额外的堆的开支来存储与这个对象的相关信息(比如方法之类的?)。我在网上看别人的文章时,有看到过“相同类实例化的对象只开辟一块空间来存储这些信息,而不是每个对象被创建时都会有这些额外开支”(我不确定是不是这样说,难道是说 被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支?)
==================================================================================
这个要从Java虚拟机的运行时数据区说起,主要有方法区、堆、Java虚拟机栈、本地方法栈、程序计数器;
方法区: 会保存已Java虚拟机加的类信息、常量、静态变量、即时编译后的代码;
堆 : 存放对象实例和数组;
Java虚拟机栈:保存局部变量表、操作数栈、方法出口等;
本地方法栈: Java虚拟机栈类似,只不过Java虚拟机栈是Java虚拟机调用Java方法,本地方法栈是Java虚拟机
调用本地方法服务;
你说的“只开辟一块空间来存储这些信息”,这个应该属于类信息,会保存在方法区中;
“难道是说 被编译时每个类都会有独立的开支,而对象被创建时又会有另外的独立开支”这样理解是正确的,
因为类信息保存在方法区,而对象实例则Java堆中。
4.如果我创建一个函数,这个函数需要被不断、大量重用,那么我是否应该尽力使传到该函数的参数为值类型(最好是byte、boolean),传递对象比传递值类型(如int)更占用内存么? 因为我最近看视频才知道,传递一个对象的话,只是传递引用,那么不管传递多大的对象,传递的引用其大小不都是一样么,而且不用额外开辟储存空间存储这个引用,这样来说穿引用不是比传值类型更占优势?
===============================================================================================
在Java基本类型都是传值,引用类型都传内存地址。传什么其实没什么区别,内存地址的范围应该int大吧。“而且不用额外开辟储存空间存储这个引用”这个很明显不可能。
5.程序在编译时,类里面的静态成员,常量就会被放到 静态、常量区,假如我在某个方法中有这样一段语句。Point p1 = new Point(1, 1); 而我写的Point类中也有自己的静态与常量成员,那这些静态成员、常量也是被分配到静态、常量区存储么?是在程序一开始编译的时候存储,还是在创建第一个该对象时临时加进去?
===============================================================================================
静态成员、常量在方法区,在类加载时加入方法区;
6.对于ArrayList,它好像是顺序表,是否意味着它在堆上的存储是连续的?那当它自己初始化的容量不足,需要扩容时,他需要重新在堆开辟空间存储新元素,那么是否有可能ArrayList在堆上就不连续了,而是一块一块的分布,那这样不就与顺序表的概念相冲突了么?
============================================================================================
ArrayList就是数组,所谓的扩容,其实就是重新分配一块更大的内存空间,再将以前的元素复制到新的内存空间,还是顺序表,没什么冲突
其实上面的问题都能在《深入Java虚拟机》中找到,而且书中描述得更详细和系统,楼主可以了解一下。