`
Heis
  • 浏览: 112622 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

三分钟理解Java中字符串(String)的存储和赋值原理

阅读更多

可能很多java的初学者对String的存储和赋值有迷惑,以下是一个很简单的测试用例,你只需要花几分钟时间便可理解。

1.在看例子之前,确保你理解以下几个术语:

 

:由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。

 

:由JVM分配的,用于存储对象等数据的区域。

 

常量池 :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.例如String str="abc"; abc这个字符串是显式声明,所以存储在常量池。

 

2.看这个例子,用JDK5+junit4.5写的例子,完全通过测试

import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;

import org.junit.Test;

/**
 * @author Heis
 *
 */
public class StringTest{

	@Test
	public void testTheSameReference1(){
		String str1="abc";
		String str2="abc";
		String str3="ab"+"c";
		String str4=new String(str2);
		
		//str1和str2引用自常量池里的同一个string对象
		assertSame(str1,str2);
		//str3通过编译优化,与str1引用自同一个对象
		assertSame(str1,str3);
		//str4因为是在堆中重新分配的另一个对象,所以它的引用与str1不同
		assertNotSame(str1,str4);
	}
	
}

 

  • 第一个断言很好理解,因为在解析的时候,"abc"被存储在常量池中,str1和str2的引用都是指向常量池中的"abc"。所以str1和str2引用是相同的。
  • 第二个断言是由于编译器做了优化,编译器会先把字符串拼接,再在常量池中查找这个字符串是否存在,如果存在,则让变量直接引用该字符串。所以str1和str3引用也是相同的。
  • str4的对象不是显式赋值的,编译器会在堆中重新分配一个区域来存储它的对象数据。所以str1和str4的引用是不一样的。


  • 大小: 62.7 KB
17
4
分享到:
评论
12 楼 asialee 2010-01-09  
这个编译优化我还真不知道,谢谢lz了。
11 楼 grunt1223 2010-01-06  
sgelove 写道
package test;

public class Test {
	public static void main(String[] args) {
		String a = "abc";
		String b = "abc";
		String c = "ab" + "c";
		String d = new String(b);
		System.out.println(a.hashCode());
		System.out.println(b.hashCode());
		System.out.println(c.hashCode());
		System.out.println(d.hashCode());
	}
}

为什么我打印出来的d和a,b,c的是一样呢?


HashCode本身就是根据字符内容计算而得的,当然一样了
比较的是引用啊~~~
10 楼 Heis 2010-01-06  
sgelove 写道
package test;

public class Test {
	public static void main(String[] args) {
		String a = "abc";
		String b = "abc";
		String c = "ab" + "c";
		String d = new String(b);
		System.out.println(a.hashCode());
		System.out.println(b.hashCode());
		System.out.println(c.hashCode());
		System.out.println(d.hashCode());
	}
}

为什么我打印出来的d和a,b,c的是一样呢?

因为你的变量a,b,c,d的值都是"abc",哈希值是由string的值计算出来的,当然相同。
9 楼 sgelove 2010-01-06  
package test;

public class Test {
	public static void main(String[] args) {
		String a = "abc";
		String b = "abc";
		String c = "ab" + "c";
		String d = new String(b);
		System.out.println(a.hashCode());
		System.out.println(b.hashCode());
		System.out.println(c.hashCode());
		System.out.println(d.hashCode());
	}
}

为什么我打印出来的d和a,b,c的是一样呢?
8 楼 Heis 2010-01-05  
melin 写道
常量池是存放在方法区中,你那个图画的有点问题。

方法区也是在堆中的,图到底有什么问题呢?
7 楼 melin 2010-01-05  
常量池是存放在方法区中,你那个图画的有点问题。
6 楼 hanjiangit 2010-01-04  
还深入点就好了
5 楼 dragonisflying 2010-01-04  
不错,确实可以帮助理解java里的string处理机制
4 楼 wangxiaoxu 2010-01-04  
文章写的不错
3 楼 ZangXT 2010-01-04  
intih 写道
引用
常量池 :在编译的阶段,在堆中分配出来的一块存储区域,用于存储显式 的String

为什么会是在编译阶段呢,内存分配活动应该都是在Runtime

你说的对
其实编译器做的是常量池表,写在class文件中,jvm加载class的时候会根据这个表的信息处理常量池。不过一般都喜欢混着说
2 楼 Heis 2010-01-03  
intih 写道
引用
常量池 :在编译的阶段,在堆中分配出来的一块存储区域,用于存储显式 的String

为什么会是在编译阶段呢,内存分配活动应该都是在Runtime

你说的对,已经做了修改了。查了一下资料,在编译期,class文件里会保存一个本地变量表(local variable table),在解析期JVM才会把这些变量表加载到常量池中。
1 楼 intih 2010-01-03  
引用
常量池 :在编译的阶段,在堆中分配出来的一块存储区域,用于存储显式 的String

为什么会是在编译阶段呢,内存分配活动应该都是在Runtime

相关推荐

Global site tag (gtag.js) - Google Analytics