java基本类型 例如 int a=1  是在栈吧;    JVM加载类的时候,会给每个类维护一个常量池,按理说,上面的值 1应该是存在于该类的常量池中。(常量池运行中在方法区吧)
他又是为什么存在于栈中呢?
    数据是如何才可以进入栈中?常量池

解决方案 »

  1.   

    这个问题挺值得学习的,int是值数据类型,与引用数据数据类型不一样,会有相应的地址来供引用,关注了,我也想知道答案。
      

  2.   

    int是基本类型,而基本类型数据是存放于栈中的。对于常量池,你一定是觉得int a = 1 ;
    1是常量对吗?生活中可以这么理解,但java中就不是了,1 只是代表一个值,所谓的常量在
    java中是指static final修饰的变量,它们是不可改变的,也就是初始化后就再也无法改变,
    这样才叫做常量,而a = 2 它就变了吧,所以是变量。java中有六大存储位置,其中我们应该
    要很清楚明白四个(栈、堆、静态域、常量池)
      

  3.   

    a=1 这个1是个常量,但是并不代表它会在常连池中,1本身这个量是在常量池中,但是a=1的这个1不是,它被jvm优化,被直接放在指令指针上,然后a=1的数值被直接存放在方法栈当前栈的索引空间中,因为索引空间是可以直接存放基本数据类型和句柄数据的。
    这么说你大概会很糊涂,但是事实是如此,jdk与jvm会将简单量优化。
      

  4.   

    只有String类型的常量和static final修饰的“变量”才算常量。
    另外,数值常量没有必要写进常量池,因为它本身就是一个跟指针一样大小的东西,装入常量池,再用一个指针读出,再写入目标变量,与直接把值写入目标变量相比,消耗大,结果一样,所以没有意义。
    关于static final,有一个小知识:
    class Test1 {
      public static final String TEST1 = "hahaha".toString();
    }class Test2 {
      public static final String TEST2 = "hahaha".toString();
    }class TestClass {
      private String a = Test1.TEST1;
      private String b = Test2.TEST2;
      ...
    }
    如果查看一下字节码,你会发现在TestClass中,a的值是从常量池获取,而b的值则是引用了Test2的TEST2。
    如果你查看Test2的字节码,你会发现"hahaha"的确是在常量池中,而TEST2的值是在运行时被赋予。
      

  5.   

    天煞的不让改回帖论坛。Test1写错了,这里更正一下
    class Test1 {
      public static final String TEST1 = "hahaha";
    }
     
    class Test2 {
      public static final String TEST2 = "hahaha".toString();
    }
     
    class TestClass {
      private String a = Test1.TEST1;
      private String b = Test2.TEST2;
      ...
    }
      

  6.   

    我的理解:
    基本类型是放在值和指针都放在栈中的;引用的对象被final static的值才会放到常量池中,指针是被放在栈中。
      

  7.   

    你的想法是对的,但是1不用放到常量池,因为jvm刚好有个指令把1放到操作数栈中。如果100000就得放到常量池了。你可以看一下jvm规范。
    至于你说的的a,是在栈中,在进入方法调用时会把局部变量分配好(编译时已确实大小),其实就是移动一下栈指针。你可以看一下函数执行的汇编代码,会更好理解一点。
      

  8.   

    可以看一下java数据存储的介绍,百度文库的,希望对楼主有帮助
    http://wenku.baidu.com/view/8c66da7e27284b73f2425056.html
      

  9.   

    我又测试了下   只有我把int 声明为final时才能够在常量池中看到,  而对于long ,double ,float string 
    即使不是final 也会在常量池中出现, short char  和int的情况相同;
       查看字节码后 那些在常量池中的都会用ldc #2.  入栈, 而对于int那样的  就是sipush 转化为int后入栈   public class wy {
        String itemS ="我们 ";
       static final  int as=6;
      Integer i1=129;
      double  a=1.23;
      long    bb=111111111;
       float  cc=1.26f;
       short  ee=55;
       char   ff='z';
       //Boolean bool1=true;

    aload_0
    invokespecial java/lang/Object/<init>()V
    aload_0
    ldc "我们 "
    putfield wy/itemS Ljava/lang/String;
    aload_0
    sipush 129
    invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
    putfield wy/i1 Ljava/lang/Integer;
    aload_0
    ldc2_w 1.23
    putfield wy/a D
    aload_0 
        这样说对不对?
      还有就是声明为int a=122  和 Integer a=122  有什么不一样?
                  int i4=444;
       Integer i3=new Integer(444);
           i3==i4 为true??
      

  10.   

    请忽略我。。让我再研究一下看下这个帖子  http://bbs.csdn.net/topics/290004554 
    看一下实际的处理情况:
           int a=3;
           int b=3;
           int c=65535;
           int d=65535;
           int e=32330;
           int f=32330;
    看对应的虚拟机指令,可以知道变量里实际存储的是什么:
    Code:
       0:        iconst_3   //3
       1:        istore_1
       2:        iconst_3   //3
       3:        istore_2
       4:        ldc        #2; //int 65535
       6:        istore_3
       7:        ldc        #2; //int 65535
       9:        istore        4
       11:        sipush        32330
       14:        istore        5
       16:        sipush        32330
       19:        istore        6
       21:        return
    可以看出每个变量保存自己的值.(具体指令的意义参考java虚拟机规范)
    这里要注意的是对于int值,如果它大于short能表示的范围,则放到常量池中去.
    11:        sipush        32330
       14:        istore        5
    这句,11-13,正好是3个字节的指令大小,一个字节是sipush指令,2个字节用来存储32330这个数.两次使用到这个数,都是把它直接存给变量的,所以原贴中一直强调的"栈中共享" 的说法明显不对.
    对于65535,它是大于两个字节的,编译的时候把它放入常量池部分,而把取这个数的指令写为ldc#2,我感觉这样一个直观的好处是减少了指令代码的长度.尤其是多次使用到一个相同的数时.
      但是e==f 为true     这个是为什么?   而且两次使用 sipush   32330(是入栈吧?)
      

  11.   

    请忽略我。。让我再研究一下看下这个帖子  http://bbs.csdn.net/topics/290004554 
    看一下实际的处理情况:
           int a=3;
           int b=3;
           int c=65535;
           int d=65535;
           int e=32330;
           int f=32330;
    看对应的虚拟机指令,可以知道变量里实际存储的是什么:
    Code:
       0:        iconst_3   //3
       1:        istore_1
       2:        iconst_3   //3
       3:        istore_2
       4:        ldc        #2; //int 65535
       6:        istore_3
       7:        ldc        #2; //int 65535
       9:        istore        4
       11:        sipush        32330
       14:        istore        5
       16:        sipush        32330
       19:        istore        6
       21:        return
    可以看出每个变量保存自己的值.(具体指令的意义参考java虚拟机规范)
    这里要注意的是对于int值,如果它大于short能表示的范围,则放到常量池中去.
    11:        sipush        32330
       14:        istore        5
    这句,11-13,正好是3个字节的指令大小,一个字节是sipush指令,2个字节用来存储32330这个数.两次使用到这个数,都是把它直接存给变量的,所以原贴中一直强调的"栈中共享" 的说法明显不对.
    对于65535,它是大于两个字节的,编译的时候把它放入常量池部分,而把取这个数的指令写为ldc#2,我感觉这样一个直观的好处是减少了指令代码的长度.尤其是多次使用到一个相同的数时.
      但是e==f 为true     这个是为什么?   而且两次使用 sipush   32330(是入栈吧?)

    谢谢大大发片!我研究了一下Java ByteCode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings 发现JVM指令里面只有bipush和sipush。另外对于integer,有-1 ~ 5的7个内置常量指令,也就是上面看到的类似iconst_3(虽然不知道为什么)。所以对于byte范围内的整数,则用bipush(byte integer push)入栈;对于short范围内的整数,用sipush(short integer push),其余则由指令LDC从常量池加载。另外一个疑惑的事情是,由64位Java编译出来的指令码,也没有"iipush"或者"ffpush"之类的东西,照理说指令长度不再有4个字节的限制,应该可以才对。。难道是为了兼容性?至于e==f为true,这不是自然的事情么只是栈头的两个数作比较而已,它们的确相同。至于为什么要调用两次sipush,是因为istore有一个出栈操作,14行之后栈是空的,必须再入栈才能执行下一个istore
      

  12.   

    java没有32与64的区分,java所有的定义都是规范化的,他不会收到cpu字长的影响,因此class文件不区分32与64,这些由jvm去处理了。
    常量池会存储所有的常量,即使是1也不例外,只是jdk在编译的时候,会优化class,将一些没有必要的常量指令化来节省class文件大小和内存加载的空间。ldc只是从常量池将数据检索出来,并无转换的过程,它将常量池的数据检索出来并压入操作数栈,然后其它指令讲操作数栈中此数出栈病存入方法栈局部变量索引中。
    其实java的执行引擎,与cpu执行引擎类似,大体上所有执行引擎的设计都是如此,java的常量池相当于内存数据,而java的指令指针相当于cpu的指令指针,它总是指向下一句代码。而局部变量相当于cpu的二级缓存,至于操作数栈,相当于寄存器。为什么说jvm是个虚拟机,因为他就像一个虚拟机一样运行。
      

  13.   

    请忽略我。。让我再研究一下看下这个帖子  http://bbs.csdn.net/topics/290004554 
    看一下实际的处理情况:
           int a=3;
           int b=3;
           int c=65535;
           int d=65535;
           int e=32330;
           int f=32330;
    看对应的虚拟机指令,可以知道变量里实际存储的是什么:
    Code:
       0:        iconst_3   //3
       1:        istore_1
       2:        iconst_3   //3
       3:        istore_2
       4:        ldc        #2; //int 65535
       6:        istore_3
       7:        ldc        #2; //int 65535
       9:        istore        4
       11:        sipush        32330
       14:        istore        5
       16:        sipush        32330
       19:        istore        6
       21:        return
    可以看出每个变量保存自己的值.(具体指令的意义参考java虚拟机规范)
    这里要注意的是对于int值,如果它大于short能表示的范围,则放到常量池中去.
    11:        sipush        32330
       14:        istore        5
    这句,11-13,正好是3个字节的指令大小,一个字节是sipush指令,2个字节用来存储32330这个数.两次使用到这个数,都是把它直接存给变量的,所以原贴中一直强调的"栈中共享" 的说法明显不对.
    对于65535,它是大于两个字节的,编译的时候把它放入常量池部分,而把取这个数的指令写为ldc#2,我感觉这样一个直观的好处是减少了指令代码的长度.尤其是多次使用到一个相同的数时.
      但是e==f 为true     这个是为什么?   而且两次使用 sipush   32330(是入栈吧?)

    谢谢大大发片!我研究了一下Java ByteCode http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings 发现JVM指令里面只有bipush和sipush。另外对于integer,有-1 ~ 5的7个内置常量指令,也就是上面看到的类似iconst_3(虽然不知道为什么)。所以对于byte范围内的整数,则用bipush(byte integer push)入栈;对于short范围内的整数,用sipush(short integer push),其余则由指令LDC从常量池加载。另外一个疑惑的事情是,由64位Java编译出来的指令码,也没有"iipush"或者"ffpush"之类的东西,照理说指令长度不再有4个字节的限制,应该可以才对。。难道是为了兼容性?至于e==f为true,这不是自然的事情么只是栈头的两个数作比较而已,它们的确相同。至于为什么要调用两次sipush,是因为istore有一个出栈操作,14行之后栈是空的,必须再入栈才能执行下一个istore e和f是局部变量吧, 那个   istore    5  是出栈把32300 赋值给 e是吧? (那e是存放在哪?)
      给f赋值的时候又入栈32300,     那么e和f 到底是不是共享32300?  是不是栈中共享? 
      

  14.   

    常量池(constant pool)是每个类或者每个接口的java class文件中的constant_pool表的运行期表示。常量池的功能类似传统的程序设计语言的符号表。每个常量池都是从 JVM 的方法区分配的。类或接口的常量池在该类或接口的   .class文件被JVM成功装载时创建。
      

  15.   

    关于e和f是否共享32300,这个既是又不是。
    e和f是两个不同变量,但是有同样的值。比方说在内存的位置0x0001和0x0005,各存放了一个32300。因为32300只是一个数字,它们永远相同。这就好比质子,它们是全等的,你从一个铁原子和一个碳原子中各拿一个质子来比,它们没有任何不同。同样,你把内存中0x0001和0x0005的32300拿来比,它们也没有不同。就是说,32300跟质子一样,虽然来自不同的地方,但它们却又是相同的
      

  16.   

    e和f是栈中两个变量,当然不会共享。
    http://bbs.csdn.net/topics/390469447#这里列出了一些扯淡的帖子,可以看看,防止上当受骗。