一、String在内存中的存储情况
1.Java虚拟机JVM的内存块及其变量、对象内存空间是怎么存储分配的?
1、栈:存放基本数据类型及对象变量的引用,对象本身不存放于栈中而是存放于堆中 1)、基础类型 byte (8位)、boolean (1位)、char (16位)、int (32位)、short (16位)、float (32位)、double (64位)、long (64位) 2)、java代码作用域中定义一个变量时,则java就在栈中为这个变量分配内存空间,当该变量退出该作用域时,java会自动释放该变量所占的空间 2、堆:new操作符的对象 1)、new创建的对象和数组 2)、在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理 3、静态域:static定义的静态成员变量 4、常量池:存放常量 |
package terry.java.base;
public class StringTest {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
String newA = new String("hello");
String newB = new String("hello");
System.out.println("****** Testing Object == ******");
System.out.println("a==b ? :" + (a==b));
System.out.println("newA==newB ? :" +(newA==newB));
System.out.println("a==newA ? :" + (a==newA));
System.out.println("***** Testing String Object intern method******");
System.out.println("a.intern()==b.intern() ? : " + (a.intern()==b.intern()));
System.out.println("newA.intern()==newB.intern() ? :" + (newA.intern()==newB.intern()));
System.out.println("a.intern()==newA.intern() ? :" + (a.intern()==newA.intern()));
System.out.println("a=a.intern() ? :" + (a==a.intern()));
System.out.println("newA==newA.intern() ? : " + (newA==newA.intern()));
System.out.println("****** Testing String Object equals method******");
System.out.println("equals() method :" + a.equals(newA));
String c = "hel";
String d = "lo";
final String finalc = "hel";
final String finalgetc = getc();
System.out.println("****** Testing Object splice ******");
System.out.println("a==\"hel\"+\"lo\" ? :" + (a=="hel"+"lo"));
System.out.println("a==c+d ? : " + (a==c+d));
System.out.println("a==c+\"lo\" ? : " + (a==c+"lo"));
System.out.println("a==finalc+\"lo\" ? :" + (a==finalc+"lo"));
System.out.println("a==finalgetc+\"lo\" ? :" + (a==finalgetc+"lo"));
}
private static String getc(){
return "hel";
}
}
********************Testing Object ************************
(1)a、b 创建的 hello 都存在于方法区中的常量池其中的字符串池,故第一条 true 。
(2) newA、newB 创建的 hello 存在于堆中,指向不同的对象,故 false 。
(3)a 创建的 hello 存在于方法区中的常量池其中的字符串池,而 newA 创建的 hello 存在于堆中,故false 。
******************Testing intern method********************
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
(1)都指向字符串常量池中的hello,所以true
(2)都指向字符串常量池中的hello,所以true
(3)都指向字符串常量池中的hello,所以true
(4)都指向字符串常量池中的hello,所以true
(5)newA指向堆中的hello对象,newA.intern()指向字符串常量池中的hello,所以为false;
*********************Testing equals method**********************
equals方法检测两个字符串的内容是否相同,而==运算符检测两个字符串是否放置在同一个位置上。
(1)a和newA内容相同,所以true;
**********************Testing Object splice**************************
(1) "hel" + "lo"的创建是先进行表达式的字符串连接,然后才进行赋值。赋值的时候会搜索池中是否有 hello 字符串,若有则指向该字符串,若没有则在池中新增该字符串。显然 “hel” + "lo" 的创建是用了a 已经创建好的字面量,故 true 。
(2) a == c + d ?; 其实相当于 a== new String(c + d) ?; new String(c + d) 是存放于堆中的,不是字面量。所以 false 。
(3)JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,所以c+\"lo\"实际是c在栈中保存的地址+字符串"lo"于常量池中指向的地址 所指向的在堆中新分配的一块内存空间,所以false
(4)对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量 池中或嵌入到它的字节码流中,在编译期就已经确定了内存空间地址,所以此类似于2个字符串常量的+ ,所以true
****** Testing Object == ******
a==b ? :true
newA==newB ? :false
a==newA ? :false
***** Testing String Object intern method******
a.intern()==b.intern() ? : true
newA.intern()==newB.intern() ? :true
a.intern()==newA.intern() ? :true
a==a.intern() ? :true
newA==newA.intern() ? : false
****** Testing String Object equals method******
equals() method :true
****** Testing Object splice ******
a=="hel"+"lo" ? :true
a==c+d ? : false
a==c+"lo" ? : false
a==finalc+"lo" ? :true
a==finalgetc+"lo" ? :false
上述各个变量及引用在JVM分配的内存情况