`

Java中的String类

阅读更多
1. 正像很多人所说的那样,equals 和 == 是完全两个不同的概念,将两者进行比较是有点滑稽的,不过对于Java的String类型来说,又使得两者之间建立了一点点联系。 要弄明白不同的String类型变量使用 “==” 操作符的结果何时为TRUE,何时为FALSE,只要将以下几点弄明白就好:
1. == 比较的是地址的引用
2. Java中的String池概念

做了个例子,如下:


/**
 * String
 * 	equals()	比较的是内容
 * 	==			比较的是引用
 * 需要注意的是java的String池。
 * 而且当一个String是由"常量的String"形成的,(如String s4 = "Mon" + "day"; s4会引用内存池中的"Monday"(如果存在的话))
 * 该String会引用内存中的String(如果存在的话).
 * @author yuahan
 * 
 */
public class _String {
	public static void main(String[] args) {
		String s1 = "Monday";
		String s2 = "Monday";
		
		System.out.println(s1 == s2);
		
		
		String s3 = new String("Monday");
		System.out.println(s1 == s3);
		
		
		s3 = s3.intern();//当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。 
		System.out.println(s1 == s3);
		
		
		String s4 = "Mon" + "day";//对于String的常量表达式,java 会判断在内存中生成了Mon 和 day 两个常量之后,合成s4时会检查是否已经存在
		System.out.println(s1 == s4);
		
		String s5 = "Monday6";
		String s6 = s1 + 6;
		final String s7 = "Monday";
		System.out.println(s5 == (s7 + 6));//true
		System.out.println(s1 == "Monday");
		System.out.println(s5 == ("Monday" + 6));//两个都是常量,故在编译时便能确定,导致引用相同
		
		System.out.println(s5 == s6);//false
		System.out.println(s5 == (s1 + 6));//false
		System.out.println(s5 == ("Monday" + s1.length()));//后者是变量,只有在执行时才能确定,引用不同
		System.out.println(s6 == ("Monday" + s1.length()));
		
		
		
		String animal1 = "animal1";
		String animal2 = "animal" + "1".length();
		System.out.println("equals? " + animal1 == animal2);// result is "false", not "equals? false".
		System.out.println("equals? " + (animal1 == animal2));// result is "equals? false".
		
	}
}




2. 栈(stack)与堆(heap)区别以及Java的string变量赋值的内部工作机制(精典转载贴)
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char。存在于栈中。另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中.
String str = "abc";和String str = new String("abc");和char[] c = {'a','b','c'};String str=new String(c);都采用堆存储
String str = "abc";在栈中如果没有存放值为"abc"的地址,等同于:
String temp=new String("abc");
String str=temp;
关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为str的对String类的对象引用变量:String str;
(2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。
(3)将str指向对象o的地址。
使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
char[] c = {'a','b','c'};String str=new String(c);等同于:
String str = new String('a'+'b'+'c');
本概念转自: http://primer-2004.iteye.com/blog/125434

3. String对象的创建

原理1:当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。
原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。
原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。

另外,String的intern()方法是一个本地方法,定义为public native String intern(); intern()方法的价值在于让开发者能将注意力集中到String池上。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。

由于Java是不可变类,这可以在一定程度上提高String创建和使用的效率。
不可改变的字符串具有一个很大的优点:编译器可以把字符串设置为共享。不可变类String有一个重要的优点-它们不会被共享引用。

是这样的,JAVA为了提高效率,所以对于String类型进行了特别的处理---为string类型提供了串池。
定义一个string类型的变量有两种方式:
string name= "tom ";
string name =new string( "tom ")
使用第一种方式的时候,就使用了串池,
使用第二中方式的时候,就是一种普通的声明对象的方式。
如果你使用了第一种方式,那么当你在声明一个内容也是 "tom "的string时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,string saname= "tom ",将会指向同一块内存

另外关于string类型是不可改变的问题:
string类型是不可改变的,也就是说,当你想改变一个string对象的时候,比如name= "madding "
那么虚拟机不会改变原来的对象,而是生成一个新的string对象,然后让name去指向它,如果原来的那个 "tom "没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。
package com.java.lang;

public class _String {
	public static void main(String[] args) {
		String str1 = "hello";
		String str2 = "world";
		String str3 = "helloworld";
		String str4 = str1 + str2;//由于str1和str2是变量,编译时不能确定 str4指向的地址。
		String str5 = "hello" + "world";//由于"hello" 和  "world"都是常量,编译时确定 str5指向的地址是跟str3一样的。
		String str6 = "hello" + str2;//由于str2是变量,编译时不能确定 str6指向的地址。
		String str7 = str1 + "world";//由于str1是变量,编译时不能确定 str7指向的地址。
		
		System.out.println(str3 == str4);//false
		System.out.println(str3 == str5);//true
		System.out.println(str3 == str6);//false
		System.out.println(str3 == str7);//false
		
	}
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics