Java把内存划分成为两种:一种是堆,一种是栈。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
栈:存放一些基本类型的变量和对象的引用变量。
优点:java自动释放掉所分配的空间,该内存空间可以立即被另作他用,存取速度比堆要快。
缺点:存在栈中的数据大小与生存期必须确定的,缺乏灵活性。
栈中主要存放一些基本类型的变量(int,short,long,byte,float,double,boolean,char)和对象引用。数据是可以共享的。假设我们同时定义:
int a=3;
int b=3;<span style="font-family: SimSun;"> </span>
堆:存放由new创建的对象和数组(可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中这个变量就成了数组或对象的引用变量,就相对于一个名字。以后就可以使用栈中的引用变量来访问堆中的数组或对象。)。是有java虚拟机自动垃圾回收器来管理的。运行时动态分配空间。因为运行时分配内存,存取速度较慢。
String str = new String("abc"); 这种是用new()来新建对象的,它会存放在堆中,每调用一次就会创建一个新的对象。
String str = "abc"; 这种是存放在栈中,创建一个String类的对象引用变量str,然后在栈中查找有没有存放abc,如果没有,则将abc存放在栈中,并令str指向abc,如果有abc,则直接令str指向abc。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true;
可以看出str1和str2是指向同一个对象的。
这里是创建了两个abc字符串,在内存中其实只存在一个对象,这种写法有利于节省内存空间,同时它也可以在一定程度上提高程序的运行速度。因为jvm会自动根据栈中数据的实际情况来决定是否有必要创建新对象。
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
System.out.println(str1==str2); //false;
System.out.println(str1==str3); //false
因为用了new,生成了两个不同的对象,是在堆中创建新的对象,而不管其他字符串值是否相等,是有必要创建新对象,从而加重了程序的负担。
由于String类是不变性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
比较类里面的数值是否相等,用equals()方法,比较两个包装类的引用是否指向同一个对象时,用==。
String str1 = "abc";
String str2 = "abc";
String str3 = "a";
String str4 = "bc";
String a = new String("abc");
String c = new String("abc");
String d = new String("a");
String e = new String("bc");
System.out.println(str1 == str2);//true
System.out.println(str1.equals(str2));//true
System.out.println(str1 == str3+str4);//false
System.out.println(str1.equals(str3+str4));//true
System.out.println(str1==a);//false
System.out.println(str1.equals(a));//true
System.out.println(a == c);//false
System.out.println(a.equals(c));//true
System.out.println(a == d+e);//false
System.out.println(a.equals(d+e));//true
结论和建议:
- 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。
- 使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。
- 当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
- 由于String类的不可改变的性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。