java 基本类型 与常量池和栈 java基本类型 例如 int a=1 是在栈吧; JVM加载类的时候,会给每个类维护一个常量池,按理说,上面的值 1应该是存在于该类的常量池中。(常量池运行中在方法区吧)他又是为什么存在于栈中呢? 数据是如何才可以进入栈中?栈常量池 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 这个问题挺值得学习的,int是值数据类型,与引用数据数据类型不一样,会有相应的地址来供引用,关注了,我也想知道答案。 int是基本类型,而基本类型数据是存放于栈中的。对于常量池,你一定是觉得int a = 1 ;1是常量对吗?生活中可以这么理解,但java中就不是了,1 只是代表一个值,所谓的常量在java中是指static final修饰的变量,它们是不可改变的,也就是初始化后就再也无法改变,这样才叫做常量,而a = 2 它就变了吧,所以是变量。java中有六大存储位置,其中我们应该要很清楚明白四个(栈、堆、静态域、常量池) a=1 这个1是个常量,但是并不代表它会在常连池中,1本身这个量是在常量池中,但是a=1的这个1不是,它被jvm优化,被直接放在指令指针上,然后a=1的数值被直接存放在方法栈当前栈的索引空间中,因为索引空间是可以直接存放基本数据类型和句柄数据的。这么说你大概会很糊涂,但是事实是如此,jdk与jvm会将简单量优化。 只有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的值是在运行时被赋予。 天煞的不让改回帖论坛。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; ...} 我的理解:基本类型是放在值和指针都放在栈中的;引用的对象被final static的值才会放到常量池中,指针是被放在栈中。 你的想法是对的,但是1不用放到常量池,因为jvm刚好有个指令把1放到操作数栈中。如果100000就得放到常量池了。你可以看一下jvm规范。至于你说的的a,是在栈中,在进入方法调用时会把局部变量分配好(编译时已确实大小),其实就是移动一下栈指针。你可以看一下函数执行的汇编代码,会更好理解一点。 可以看一下java数据存储的介绍,百度文库的,希望对楼主有帮助http://wenku.baidu.com/view/8c66da7e27284b73f2425056.html 我又测试了下 只有我把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_0invokespecial java/lang/Object/<init>()Vaload_0ldc "我们 "putfield wy/itemS Ljava/lang/String;aload_0sipush 129invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;putfield wy/i1 Ljava/lang/Integer;aload_0ldc2_w 1.23putfield wy/a Daload_0 这样说对不对? 还有就是声明为int a=122 和 Integer a=122 有什么不一样? int i4=444; Integer i3=new Integer(444); i3==i4 为true?? 请忽略我。。让我再研究一下看下这个帖子 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(是入栈吧?) 请忽略我。。让我再研究一下看下这个帖子 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 java没有32与64的区分,java所有的定义都是规范化的,他不会收到cpu字长的影响,因此class文件不区分32与64,这些由jvm去处理了。常量池会存储所有的常量,即使是1也不例外,只是jdk在编译的时候,会优化class,将一些没有必要的常量指令化来节省class文件大小和内存加载的空间。ldc只是从常量池将数据检索出来,并无转换的过程,它将常量池的数据检索出来并压入操作数栈,然后其它指令讲操作数栈中此数出栈病存入方法栈局部变量索引中。其实java的执行引擎,与cpu执行引擎类似,大体上所有执行引擎的设计都是如此,java的常量池相当于内存数据,而java的指令指针相当于cpu的指令指针,它总是指向下一句代码。而局部变量相当于cpu的二级缓存,至于操作数栈,相当于寄存器。为什么说jvm是个虚拟机,因为他就像一个虚拟机一样运行。 请忽略我。。让我再研究一下看下这个帖子 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? 是不是栈中共享? 常量池(constant pool)是每个类或者每个接口的java class文件中的constant_pool表的运行期表示。常量池的功能类似传统的程序设计语言的符号表。每个常量池都是从 JVM 的方法区分配的。类或接口的常量池在该类或接口的 .class文件被JVM成功装载时创建。 关于e和f是否共享32300,这个既是又不是。e和f是两个不同变量,但是有同样的值。比方说在内存的位置0x0001和0x0005,各存放了一个32300。因为32300只是一个数字,它们永远相同。这就好比质子,它们是全等的,你从一个铁原子和一个碳原子中各拿一个质子来比,它们没有任何不同。同样,你把内存中0x0001和0x0005的32300拿来比,它们也没有不同。就是说,32300跟质子一样,虽然来自不同的地方,但它们却又是相同的 e和f是栈中两个变量,当然不会共享。http://bbs.csdn.net/topics/390469447#这里列出了一些扯淡的帖子,可以看看,防止上当受骗。 关于利用递归求给定字符串的全排列 J2SE学通大概要花多厂时间? 千古奇观,为什么会插不进去呢,并且不报任何错误。。。 在jpanel上绘图 如果图比较大 显示不完 想要做下拉条 高手帮忙指点下!谢谢 JAVA开发者的高手的QQ群,号码是4338365,群主将定期删除不活跃的人员. 求助(初学者问题) java程序运行问题 如何在win2000professional安装Emacs21.2? [公告]撤销sharetop的版主职务 想报一个培训班学习软件编程,我该怎么选择,谢谢各位! 求大神帮忙:java带pfx证书获取https内容 java异常
1是常量对吗?生活中可以这么理解,但java中就不是了,1 只是代表一个值,所谓的常量在
java中是指static final修饰的变量,它们是不可改变的,也就是初始化后就再也无法改变,
这样才叫做常量,而a = 2 它就变了吧,所以是变量。java中有六大存储位置,其中我们应该
要很清楚明白四个(栈、堆、静态域、常量池)
这么说你大概会很糊涂,但是事实是如此,jdk与jvm会将简单量优化。
另外,数值常量没有必要写进常量池,因为它本身就是一个跟指针一样大小的东西,装入常量池,再用一个指针读出,再写入目标变量,与直接把值写入目标变量相比,消耗大,结果一样,所以没有意义。
关于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的值是在运行时被赋予。
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;
...
}
基本类型是放在值和指针都放在栈中的;引用的对象被final static的值才会放到常量池中,指针是被放在栈中。
至于你说的的a,是在栈中,在进入方法调用时会把局部变量分配好(编译时已确实大小),其实就是移动一下栈指针。你可以看一下函数执行的汇编代码,会更好理解一点。
http://wenku.baidu.com/view/8c66da7e27284b73f2425056.html
即使不是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??
看一下实际的处理情况:
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(是入栈吧?)
看一下实际的处理情况:
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
常量池会存储所有的常量,即使是1也不例外,只是jdk在编译的时候,会优化class,将一些没有必要的常量指令化来节省class文件大小和内存加载的空间。ldc只是从常量池将数据检索出来,并无转换的过程,它将常量池的数据检索出来并压入操作数栈,然后其它指令讲操作数栈中此数出栈病存入方法栈局部变量索引中。
其实java的执行引擎,与cpu执行引擎类似,大体上所有执行引擎的设计都是如此,java的常量池相当于内存数据,而java的指令指针相当于cpu的指令指针,它总是指向下一句代码。而局部变量相当于cpu的二级缓存,至于操作数栈,相当于寄存器。为什么说jvm是个虚拟机,因为他就像一个虚拟机一样运行。
看一下实际的处理情况:
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? 是不是栈中共享?
e和f是两个不同变量,但是有同样的值。比方说在内存的位置0x0001和0x0005,各存放了一个32300。因为32300只是一个数字,它们永远相同。这就好比质子,它们是全等的,你从一个铁原子和一个碳原子中各拿一个质子来比,它们没有任何不同。同样,你把内存中0x0001和0x0005的32300拿来比,它们也没有不同。就是说,32300跟质子一样,虽然来自不同的地方,但它们却又是相同的
http://bbs.csdn.net/topics/390469447#这里列出了一些扯淡的帖子,可以看看,防止上当受骗。