您的位置:首页 > 编程语言 > Java开发

java各变量的存储位置

2015-10-07 16:19 323 查看
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 
2.:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new
出来的对象)或者常量池中(字符串常量对象存放在常量池中。) 
3.:存放所有new出来的对象。 
4.
静态域:存放静态成员(static定义的) 
5.
常量池:存放字符串常量和基本类型常量(public static
final)。 
6.
非RAM存储:硬盘等永久存储空间 

String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。 先产生XYZ,再创建S

栈:包括java虚拟机栈(传统意义的栈)与本地方法栈。这里介绍java虚拟机栈:存放基本类型的变量数据、动态链接、方法出口、对象的引用等,但对象本身不存放在栈中,而是存放在堆(new
出来的对象)或者常量池中。 

  当在一段代码块定义一个变量时,Java就在栈中 为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。

      堆:内存用来存放由new创建的对象和数组。
在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。方法中的局部变量使用final修饰后,也是放在堆中,而不是栈中(注意final修饰的字符串常量除外)。

      方法区(又称静态存储区):用于存储已被虚拟机加载的类信息、常量、静态变量、编译后的代码等数据。包括静态域、常量池等。其中静态域存放的是 static
定义的变量;常量池存放字符串常量、public static
final修饰的基本类型常量。

    堆与栈

  这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负
4000
责回收,因此大小和生命周期不需要确定,具有很大的灵活性,但缺点是,由于要在运行时动态
分配内存,存取速度较慢。

  栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是 确定的,缺乏灵活性。栈中主要存放一些基本类型的变量数据(int, short, long, byte, float, double, boolean, char)和对象句柄(引用)。

       栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

  Java代码

  int a = 3;

  int b = 3;

  编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。另外注意这里的a是一个指向int类型的引用,指向3这个字面值,这些字面值的数据,由于大小可知,生存期可知(这些字面值定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中,也就是说字面值3存储在栈中。

  这时,如果再令 a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响 到b的值。

  要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

Java代码 

1.int i1 = 9;  

2.int i2 = 9;  

3.int i3 = 9;   

4.public static final int INT1 = 9;  

5.public static final int INT2 = 9;  

6.public static final int INT3 = 9;  

对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。 
形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。 
成员变量存储在堆中的对象里面,由垃圾回收器负责回收。 

      常量池 (constant pool)

    常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:

  ◆类和接口的全限定名;

  ◆字段的名称和描述符;

  ◆方法和名称和描述符。

如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  存储