事情经过是这样的:
int a=3; 就当局部变量好了我一直没搞明白的是,a变量在编译器编译之后 其实就是一个地址了。比如0x00001那把数值3赋值给a,其实就是给地址0x00001里写入数值3是吗?那我可以这么理解吗 编译后的文件 数据其实都是在硬盘里躺着的,还没有运行,那么在硬盘里的数据是一个什么情况的状态?是不是变量a已经变成地址0x00001 数值3变成二进制11然后当程序运行时,就把数值11写入到0x00001里面去了?但是我还有个疑问 数值3本身还有一个自己的空间吗?比如它自己还有一个地址空间是0x00002 然后先把3写到它自己的地址里,然后0x00001在指向0x00002的地址? 如果是这样的话,那请问0x00001里面装的是地址0x00002这个地址还是0x00002里面的值11? 还是说根本就没0x00002这个地址,直接把11就写入到0x00001里就OK了?
那其实编译后的文件里 其实里面格式应该是这样 0x00001=11; 我觉着要是这样就简单多了但是说这时候有个int b=3 b也指向3 可以共享数值3的,那这么说的话 b和a 都应该指向数值3,那到底3有没有地址来保存它呢?要是没地址,赋值给0x00001后就没有了啊,那b上哪指向数值3去哦,难不成b指向0x00001地址获取数值?所以我晕了,常数到底编译时候 给不给地址啊 还是等程序运行时候加载时候 内存才分配地址?不应该是这样 要是分配也应该是编译的时候就应该给分配地址才对所以我晕了,求大神们指点下我这个迷糊的羔羊吧。
int a=3; 就当局部变量好了我一直没搞明白的是,a变量在编译器编译之后 其实就是一个地址了。比如0x00001那把数值3赋值给a,其实就是给地址0x00001里写入数值3是吗?那我可以这么理解吗 编译后的文件 数据其实都是在硬盘里躺着的,还没有运行,那么在硬盘里的数据是一个什么情况的状态?是不是变量a已经变成地址0x00001 数值3变成二进制11然后当程序运行时,就把数值11写入到0x00001里面去了?但是我还有个疑问 数值3本身还有一个自己的空间吗?比如它自己还有一个地址空间是0x00002 然后先把3写到它自己的地址里,然后0x00001在指向0x00002的地址? 如果是这样的话,那请问0x00001里面装的是地址0x00002这个地址还是0x00002里面的值11? 还是说根本就没0x00002这个地址,直接把11就写入到0x00001里就OK了?
那其实编译后的文件里 其实里面格式应该是这样 0x00001=11; 我觉着要是这样就简单多了但是说这时候有个int b=3 b也指向3 可以共享数值3的,那这么说的话 b和a 都应该指向数值3,那到底3有没有地址来保存它呢?要是没地址,赋值给0x00001后就没有了啊,那b上哪指向数值3去哦,难不成b指向0x00001地址获取数值?所以我晕了,常数到底编译时候 给不给地址啊 还是等程序运行时候加载时候 内存才分配地址?不应该是这样 要是分配也应该是编译的时候就应该给分配地址才对所以我晕了,求大神们指点下我这个迷糊的羔羊吧。
public class A{
int a=3;
}
java加载A时,会解析A类的代码,寻找其中的常量,也就是不会在变的量。
如:
3 , 9.9 , “test”
然后在加载时,会在java的一个叫常量池的地方去寻找有没有3这个常量。如果没有,就在常量池中建一个3,也就是在内存中某个位置赋值11.当java初始化A时,执行int a=3;
首先,在栈中开辟一个空间作为a,然后从常量池中取得3的内存地址,将这个地址赋给a.换句话说,a里面存的是地址,而不是值。
这也是为什么你
int b=3;
a和b能相等的原因。理由:int a=1;
int b=a;
a=2;
System.out.println(b);print:1
如果b只是简单的指向a的话,a的值改变,b也会变的,但是结果b没变。就是因为刚开始a和b都指向常量池中1的地址值。然后a指向了2的地址值。但是b指向的地址值并没有变。当然,如果楼主理解的更加细致的话,就需要看看JVM的工作原理了。
这个算是class文件 但是还没运行哦然后开始运行了,加载到虚拟机里,先到栈里找常量3,因为class文件一直都在硬盘上没有运行,现在刚开始运行加载,常量池里肯定是什么都没有才对,那么没有找到3,这样就先开辟一个内存地址假设为0x00002,然后把class文件里的常量3直接写入栈里刚开辟的那个空间0x00002里,好了现在常量池有数值3了,继续下一步,读取class文件里的变量a,因为编译后a已经变成某个0x00001地址了,这时候虚拟机继续又在栈里开辟一个0x00001地址空间,最后在把刚才0x00002地址放进0x00001里,所以变量a里存的是常量3的地址0x00002.你帮我看看是不是这样的过程?
明白了,但是我还想问下,因为int是基本类型,这里没有类,所以常量池在栈里直接保存,但是还有一个常量池好像是在堆里,比如当new对象时候,引用变量还在栈里,但是对象在堆里,然后对象所指向堆里的常量池,是不是这样?我感觉常量池有好几个,不同类型有不同的常量池,有的在栈里,有的在堆里 是不是?应该是基本类型的int long什么的 直接在栈里有常量池然后String new对象什么的 都是在堆里 有常量池最后再问下,在编译器编译的时候,int a=3 是不是先编译成这样 int 0x00001=11(二进制3)
这个算是class文件 但是还没运行哦然后开始运行了,加载到虚拟机里,先到栈里找常量3,因为class文件一直都在硬盘上没有运行,现在刚开始运行加载,常量池里肯定是什么都没有才对,那么没有找到3,这样就先开辟一个内存地址假设为0x00002,然后把class文件里的常量3直接写入栈里刚开辟的那个空间0x00002里,好了现在常量池有数值3了,继续下一步,读取class文件里的变量a,因为编译后a已经变成某个0x00001地址了,这时候虚拟机继续又在栈里开辟一个0x00001地址空间,最后在把刚才0x00002地址放进0x00001里,所以变量a里存的是常量3的地址0x00002.你帮我看看是不是这样的过程?
你可以简单的理解为首先在内存里面(其实是方法区的静态常量区),内存地址假如是0x0001
那么这个时候a保存的只是"abc"的引用,也就是地址,也就是说是0x0001.
内存地址0x0001的值变了,自然a也就变了。
所有引用都是在栈中。
而对象都在堆中。
常量池就一个。但是我记得一个常量实例并不是单独的1,2,“123”。而是类似于这种的{type:int,value:1}。也就是说常量类型+常量值一体的。过程:
第一步:JVM(虚拟机)将class文件加载到内存中。
第二步:初始化类
第三步:执行int a.并在栈中开辟一个空间,作为a引用的位置。那么此时a的值是什么呢,a现在有值吗?有。作为int。初始值为0.也就是在常量池中创建了一个0.并取得0所在内存中的地址,将这个地址赋给a。
第四步:对a赋指定的值。也就是执行a=1。在常量池中寻找int类型的1,找不到,创建1,然后将1在内存中的地址赋给a。也就是说a现在的值是1在内存中的地址。
http://baike.baidu.com/view/8680346.htm