String s1 = "java1"; // 语句1
s1 += " great"; // 语句2
StringBuffer s2 = new StringBuffer("java2"); // 语句3
s2.append(" great"); // 语句4
首先回答你的问题: String不能发生变化。
String属于不可变类,创建这个类的实例,其实是声明了一个指向字符串"java1"的引用s1,由于不可变类不会提供改写或是修改成员变量的任何方法,因此String的值本身不能发生变化。语句2的作用只不过是让s1指向了另一个String类型的对象"java1 great"而已,"java1"仍存在于内存中,直到等待gc回收。
StringBuffer的状态可以发生改变,创建这个类的实例,其实是声明了一个指向字符串"java2"的引用s2,由于StringBuffer并非是不可变类,它本身支持改变状态,因此语句4执行后,会让s2指向的存放在内存中的字符串发生改变,即"java2"=》 "java2 great"。
看
过上面例子的童鞋一定会觉得很奇怪,s = s + s1.charAt(i); 马克-to-win, s不是老在变化吗?其实s =
"";时,虚拟机会创建一个String对象,s = s + s1.charAt(i);
时,会创建一个新对象,而不是之前的s了,会导致新对象的生成,这样做次数少还没有太大的问题,如果次数多的话,很浪费空间。StringBuffer是
在同一个实例上做这些事,不用生成新对象。当做的次数多的话,会节省大量空间。
java堆和栈的区别
Java中内存分成两种:一种是栈stack,一种是堆heap。
函数中的一些基本类型的变量(int, float)和对象的引用变量(reference)都在函数的栈中,马克-to-win,(工作于编译阶段, 生成class文件之前)分配。存取速度快,稍逊于寄存器, 比堆快,
函数执行完后,Java会自动释放掉为函数里变量开辟的栈内存空间,该内存空间可以立即被另作他用。
堆heap内存用来存放由new创建的对象和数组。堆内存,负责运行时(runtime, 执行生成的class文件时)数据,由JVM的自动管理。缺点是,存取速度较慢。
栈中的引用变量指向堆中的对象或数组。
栈
中有共享池的概念,比如下面例子中,sz="hello";在栈中创建一个String对象引用变量sz,然后看看栈中有没有"hello",如果没有,
则将"hello"存放进栈,并令sz指向”hello”,如果已经有”hello” 则直接令sz指向“hello”。对于int, float
类型的变量也是一样的有这种共享池的概念,注意上述的工作是在compile(编译)的阶段完成的,而不是runtime运行时完成的。
对
于下面程序中:ss0 = new String( "hello"
);是用new()来新建对象的,存于堆中。每调用一次就会创建一个新的对象。当然从节省空间的角度来讲,肯定不如str="hello",有童鞋一定
问,那要它有什么用?当时设计编译器时,为什么要设计它?马克-to-win,那我请问你,如果在你编程序时,你还不知道字符串内容怎么办?这时就用到
new String,所以,什么都有什么的用处。
本章源码
public class Test
{
public static void main(String args[]) {
String str, str1, ss0, ss1, ss2, ss3, ss4;
。。。。。。。。。。。详情网上找“马克-to-win”,参考他的网站或他的百度空间:java第2章的内容
String不能,StringBuffer能,且性能更好,推荐后者
当然不能变化,
区别当然是可变和不可变了