事情经过是这样的:
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地址获取数值?所以我晕了,常数到底编译时候 给不给地址啊 还是等程序运行时候加载时候 内存才分配地址?不应该是这样 要是分配也应该是编译的时候就应该给分配地址才对所以我晕了,求大神们指点下我这个迷糊的羔羊吧。

解决方案 »

  1.   

    假设代码如下:
    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的工作原理了。
      

  2.   

    明白了,但是我还想问下,因为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.你帮我看看是不是这样的过程?
      

  3.   


    明白了,但是我还想问下,因为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.你帮我看看是不是这样的过程?
      

  4.   

    换句话说,a里面存的是地址,而不是值。 这也是为什么你 int b=3; a和b能相等的原因这个我现在基本明白了,但是我还有个疑问,如果说存的是地址,那根据地址找到3以后怎么办?是不是应该在把3写回到a的空间去?你总不能找到3以后直接就用3吧 别忘了3是个普通数而已,你只有把3写到a自己的空间里 才能算int类型,那如果在写回去的话,那原来你说保存的地址怎么办?直接覆盖掉吗,因为我根据地址已经找到3了 我现在要赋值了对吧 那你空间里必须给我留出位置 然后我在赋值,所以赋值的时候怎么处理的 是覆盖掉原来保存的地址吗?
      

  5.   

    假如你定义了String a="abc";
    你可以简单的理解为首先在内存里面(其实是方法区的静态常量区),内存地址假如是0x0001
    那么这个时候a保存的只是"abc"的引用,也就是地址,也就是说是0x0001.
    内存地址0x0001的值变了,自然a也就变了。
      

  6.   

    我现在就一个疑问了 我就问 变量a地址里 存的不是 3的地址吗 ,那通过地址找到值3 以后怎么办?要不要把3读进变量a的地址里?如果要 请问变量a原理空间里存的地址 怎么着?是覆盖掉 还是在找值3的时候 就消失了 没有了?我现在就这一点 不理解 ,其它的都清楚了如果我说的还不清楚 或者底层比较抽象 那我用比喻的方式来 描述下比如有2个箱子  代表2块内存空间 分别编号为01号箱子 02号箱子 01和02就好比内存地址了!然后,现在01箱子里存了一个纸条上面写着02编号,02号箱子里存一个橘子,然后有个人不知道橘子在哪里,现在他打开01箱子,看到里面的纸条上面的02编号,于是在找到02的箱子,找到里面最终的橘子!我现在就想知道 这橘子最后是不是还要放回到(相当把值读回去)01箱子里去?如果是那01箱子里的那个纸条是没有了 还是被橘子覆盖掉了 还是怎么消失了 我就想知道这个?
      

  7.   

    常量池是单独的一个,关系和堆栈并列。
    所有引用都是在栈中。
    而对象都在堆中。
    常量池就一个。但是我记得一个常量实例并不是单独的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在内存中的地址。
      

  8.   

    参考这个:
    http://baike.baidu.com/view/8680346.htm