第一个重要知识点
== 和equals 方法的区别,很重要的一点为,
== 永远比较的是地址,除了在原生数据类型时比较大小
而equals方法在 String类型 和 八种原生数据类型的包装类型如Integer等,的里面是比较的内容。而对于普通的对象,equals方法也比较的是 地址。
第二个重要知识点
new的原生数据类型,原生数据类型的包装型(但是有值一定的定义域,例如integer的域为-128—+127) 例如 Integer integer=100; 通过String a=”aaa” 定义的变量,是放在栈中的,
而 new出来的对象,和a=new String(“aaa”) 是存放在堆中的, 注意Integer integer=300,因为超出了字符串常量池维护的范围,所以它是通过new来创建的,也是放在堆中的
equals 方法是在java.lang.Object 下的,它本身的源码为:
public boolean equals(Object obj) {
return (this == obj);
}
由此可见,如果equals方法没有被重写的话,它比较的应该是两个对象的地址。
注意(1):
如果: StringBuffer s1 = new StringBuffer(“a”);
StringBuffer s2 = new StringBuffer(“a”);
结果: s1.equals(s2) //是false
解释:StringBuffer:线程安全的可变字符序列,字符串长度可变StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类,
而Object类中的equals方法是用来比较“地址”的,所以等于false.
String 是一个比较特殊的类,因为比较常用,所以其的一些方法跟其他的类的方法有些不同,这是为了提高程序运行的效率,java专门重写了它的equals方法,下面是它的源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
//判断anObject是不是String类型的
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
//首先比较字符串长度的大小,
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//再逐字符的进行比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
由此可见,String类型的equals方法是比较两个字符串的内容的,
对于String 类型,它的 == 符号比较的是两个对象的地址。
对于八种原生数据类型 int,float,double,boolean,char,long,short,byte,他们的 == 比较的是两个对象的内容,他们并没有什么 equals 方法,
但是对于 八种基本类型的包装类型, Integer,Boolean、Character、Byte、Shot、Long、Float、Double是有着equals 方法,其中equals 方法比较的是它们自身的内容,而==比较的则是它们的地址
如何实现 原生数据类型和 其包装型的转化(以Integer为例子):
Integer integer=new Integer(i);
String 类型的详解:
public class StringTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// String 是常量, 一旦生成之后就不能被改变了 , + 代表拼接,生成了一个新的对象
String strr1 = "Hello";
String stre2 = " World";
String strr3= strr1 + stre2;
// 所有new出来的对象则都存放在 堆 中,而字符串池维护的则存放在栈中
// new String() 时,首先在 String 池中检查是否有“aaa” 对象,如果有,则不再在池中创建新的对象,然后再在堆中创建
//一个新的“aaa” 对象,将地址返回给 str1; 如果没有,则现在池中创建新的对象“aaa”, 然后再在堆中创建一个新的“aaa” 对象,将地址返回给 str1
String str1 = new String("aaa");
String str2 = new String("aaa");
System.out.println( str1==str2); // False
String str3 = "aaa";
String str4 = "bbb";
// 通过这种方法,String 会维护一个 String 池, 如果池里面已经有内容 为aaa 这个对象 ,则不会创建新的对象,
// 直接把之前的对象的地址赋给str5
// java 中 String == 判断的是对象的地址是否相同, 如果要判断内容是否相同,请使用 equals() 方法
String str5 = "aaa";
System.out.println( str3==str4); // False
System.out.println( str3==str5); // true
System.out.println( str3==str1); // false
}
}
String, StringBuffer/StringBuilder 的区别
第一: String(无法添加新的内容,只能通过+号拼接字符串,但其实是生成了一个新的对象) 和 StringBuffer/StringBuilder(它添加新的内容时使用append()方法,不再创建新的对象,在原来的字符串上的基础上相加)
第二: 三者速度的比较, String>StringBuilder>StringBuffer
第三:StringBuilder:可变字符串,线程非安全的, 一般单线程的时候使用,速度快
StringBuffer:可变字符串,线程安全的,除了线程安全方面的问题,其他方面的实现, StringBuffer和StringBuilder是一样的
// String 只读字符串,意味着引用的字符串内容是不可以被修改的
// StringBuilder:可变字符串,线程非安全的, 一般单线程的时候使用,速度快
// StringBuffer:可变字符串,线程安全的,除了线程安全方面的问题,其他方面的实现StringBuffer和StringBuilder是一样的
String s1="helloworld";
String s2=new String ("helloworld");
String s3="hello";
String s4="world";
String s5="hello"+"world"; // 这里你可能跟下面的一句搞混,这里其实就等价于 s5="helloworld";
// String 的intern()方法会比较看是否在常量池中有跟要创建的对象内容相同的,调用equals方法,
//如果查找到相同的,就不再创建新的对象,会得到字符串对象在常量池中的引用将其返回,所以s5也指向了s1
String s6=s3+s4; // +号操作实际上是创建了StringBulider对象,进行append操作,
// 然后将拼接后的StringBulider对象用toString方法处理成String, 所以这里是new了一个新的对象
System.out.println(s1==s2); // fasle
System.out.println(s1==s5); //true
System.out.println(s1==s6); // false
System.out.println(s2==s5); // false
System.out.println(s2==s6); // false
String 的intern() 机制
intern() 这个方法返回的是 返回字符串对象的规范化表示形式,当调用 intern 方法时,如果字符串常量池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。
String a = "b" ;
String b = "b" ;
System.out.print( a == b); // true
// intern() 这个方法返回的是 返回字符串对象的规范化表示形式,当调用 intern 方法时,如果字符串常量池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。
//否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。这时候c和d就是相同的
String c = "d" ;
String d = new String( "d" ).intern() ;
System.out.println( c == d); // true