一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。
另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: 复制内容到剪贴板代码: int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。
大体分析一下 1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 //栈都是由运行环境来处理的,这点C++和java没有什么不同.对于堆,不过java多了个GC. 2.这里的堆和栈首先要明确是虚拟机栈,和寄存器根本不是一个级别的东西,就别比较了. 3.栈数据共享好像是作者自己创造的概念.而且给基本类型也引入了"引用"的概念,不知道出于何种打算. java虚拟机规范中说:Primitive values do not share state with other primitive values. A variable whose type is a primitive type always holds a primitive value of that type. 看一下实际的处理情况: 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,我感觉这样一个直观的好处是减少了指令代码的长度.尤其是多次使用到一个相同的数时.
就拿"栈中的数据可以共享"这个荒谬的观点开刀。文章说道 [b]int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。 [/b]