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

String内存模型

2016-05-24 13:30 447 查看
1、Java内存模型: 
编程时你需要考虑的不是内存的物理地址(memory address),而是一种逻辑上的内存模型。Java虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、Java栈和Java堆。 

方法区是静态分配(static allocation)的,编译器将变量在绑定在某个存储位置上,而且这些绑定不会在运行时改变。Java方法区的一个
重要部分,也是静态分配最典型的例子,是常数池,源代码中的命名常量、String常量和static 变量保存在其中。 
Java Stack是一个逻辑概念,特点是后进先出,此外没有特别的要求。Java Stack并不代表任何特定的内存区间,也不限制它的实现方式。一
个栈的空间可能是连续的,也可能是不连续的。最典型的Stack应用是方法的调用,Java虚拟机每调用一次方法就创建一个方法帧(frame),退出该 方法则对应的方法帧被弹出(pop)。栈分配存在一些局限:Java栈所处理的方法帧和局部变量,都将随着方法帧弹出而结束,显然局部变量无法从一个帧保 持到下一个帧,被调方法的帧不可能比调用方法的寿命更长。因此,从数据保存来看,栈分配适用于由作用域决定生命周期的局部变量。 
Java堆(Heap)堆分配(heap allocation)意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。堆中存储的数据常常是大小、数量和生命期在编译时无法确定的。Java对象的内存总是在heap中分配。 

2、有人问,基本类型变量和引用变量在哪里分配空间,这不是一个有效的问题。基本类型变量和引用变量都可能保存在stack或heap中,关键是看它们声明的位置——到底是域还是局部变量。参考,“引用在哪里分配空间?”  http://blog.csdn.net/yqj2065/archive/2008/11/25/3365726.aspx 
3、“封装器”(wrapper)类。事实上,Integer、Double等包装类和String有着同样的特性:不变类。 
String str = "abc"的内部工作机制很有代表性,这里我以Boolean为例,说明同样的问题。 
不变类的属性一般定义为final,一旦构造完毕就不能再改变了。 
于是private final boolean value; 
而且由于Boolean对象只有有限的两种状态:true和false,将这两个Boolean对象定义为命名常量: 
public static final Boolean TRUE = new Boolean(true); 
public static final Boolean FALSE = new Boolean(false); 
这两个命名常量和字符串常量一样,在常数池中分配空间。 
你注意到,Boolean.TRUE是一个引用,Boolean.FALSE是一个引用,而"abc"也是一个引用!(虽然我们经常把它混用地说成字符串对象。) 

由于Boolean.TRUE是类变量(static)将静态地分配内存,所以需要很多Boolean对象时,并不需要用new表达式创建各个实例,完全可以共享这两个静态变量。其JDK中源代码是: 
public static Boolean valueOf(boolean b) { 
return (b ? TRUE : FALSE); 

基本数据(Primitive)类型的自动装箱(autoboxing)、拆箱(unboxing)是JSE 5.0提供的新功能。自动装箱与拆箱的功能事实上是编译器帮了你一点忙, 
Boolean b1 = 5>3; 
等价于Boolean b1 = Boolean.valueOf(5>3); 
//优于Boolean b1 = new Boolean (5>3); 

    static void foo(){ 
        boolean isTrue = 5>3;  //基本类型 
        Boolean b1 = Boolean.TRUE; //静态变量创建的对象 
        Boolean b2 = Boolean.valueOf(isTrue);//静态工厂 
        Boolean b3 = 5>3;//自动装箱(autoboxing) 
        System.out.println("b1 == b2 ?" +(b1 == b2)); 
        System.out.println("b1 == b3 ?" +(b1 == b3)); 
        
        Boolean b4 = new Boolean(isTrue);////不宜使用 
        System.out.println("b1 == b4 ?" +(b1 == b4));//浪费内存、有创建实例的时间开销 
    } 
这里b1、b2、b3指向同一个Boolean对象。 

4、String的特殊性 
由于String使用非常频繁,String常量也在常数池中静态分配内存。String str = "abc"的内部工作是这样的: 
Java编译器首先扫描整个程序(简化地说),把其中所有的String常量收集起来,不同则分别“创建”一个String对象。 
String str;其中str是一个引用。注意"abc"是一个引用。 
因此: 
String str1 = "abc"; 
String str2 = "abc"; 
String str3 = "ab"+"c";//同样 
//str1 = "bcd"; 
System.out.println(str1==str2); //true 
这里,str1、str2和 "abc"指向同一个String对象。它们都指向常数池中的那个对象。 
==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回true。 
如果str1指向同"bcd",则输出false。 

再举一例: 
public class A{ 
    String x ="abc"; 

public class B{ 
    String x 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  string equals jvm java