不论是对于C++还是Java,字符串总是很重要的一块内容。实际的开发中,字符串相关的内容自然也是要被经常用到的。
关于“==”以及equal 以及hashcode
在这之前要补充一点关于Object类的相关知识:
Java.lang包是系统自动导入进来的,Object类在lang包中。
对于原生数据类型而言“==”自然就是比较两个数据类型所代表的数字是否相等。
对于引用类型而言,“==”表示的是左边引用与右边的引用是否指向的是同一个对象,即使仅仅比较的是地址,而非所指向的内容,就是说仅仅比较的是左右两边的引用地址是否相同。
直接打印一个引用类型,会默认自动调用toString方法,在Object类型本来的定义中,toString方法会打印出如下的内容:getClass().getName()+’@’+Integer.toHexString(hashcode())即是打印对象所属的类名加上这个对象的引用所指向的地址的16进制表示形式。在String类中,toString方法被进行了重写,直接打印出的是字符串所指的内容,HashCode方法也进行了重写,这个hashcode值不在是跟引用所指向的内存地址有关,而是跟String实例的实际内容有关,对于不同的String类型的引用,如果有相同的内容,则他们的hashcode也是相同的。
想要比较两个字符串的内容,就要通过equal方法来比较了,注意Srring类中对equals方法进行了重写,在Object类中,equals方法相当简易与“==”是等价的,就是比较引用所指向的地址是否相同:
public boolean equals(Object obj) {
return (this == obj);
}
在String方法中重写的部分还是要特别留意一下源码,主要是借鉴这种模式,要有完整性和容错性,比如开始两步的判断。因为在许多情况下,都需要重写equals方法,这个笔试的时候也比较容易考察,String类的equals方法如下:
public boolean equals(Object anObject) {
//要是引用所指向的地址一样 直接返回true不再比较
if (this == anObject) {
return true;
}
//因为形参是Object类型的 判断如果是string类型的实例则依此比较字符 否则返回false
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;
}
//一般这种boolean类型的,也可以先默认设一个返回值,比如函数开始的时候让b=false在中间根据实际情况对b进行调整,在最后return b。
如果面试的时候,让解释equals方法,一定要分开说,对于Object类是怎样的,对于其他类,重写的话是怎样的没重写的话是怎样的。
关于字符串池
String的两种赋值方式:
String s=”hello”这种方式叫做字面赋值方式
String s=new String(“hello”)这个是通过new的方式来创建字符串对象。
因为String类在实际开发中使用得非常频繁,有必要维护一个字符串池,字符串池是栈内存中的一段空间,主要有以下的功能:
通过字面赋值的方式生成String对象,比如String s=”hello”:
1、 从String Pool中检查,看是否有hello这个对象,
2、 要是没有就在字符串池中创建一个hello对象,之后返回这个字符串池中的地址。
3、 要是字符串池中存在hello对象就返回这个hello对象的地址。
通过new的方式生成String对象,比如String s=new String(“hello”)
1、 首先在字符串池中检查是否有hello对象
2、 若是字符串池中存在hello对象,则直接在堆中创建一个hello对象,并返回堆中的地址。
3、 若是字符串池中没有hello对象,则首先在字符串池中创建hello对象,再在堆中创建hello对象,之后将堆中的地址返回。
对于上面的基本知识了解清楚,处理这个常见的String的比较问题就比较容易了:
public class stringTest {
public static void main(String[]args){
String str1="hello";//str1指向的是字符串池中的地址
String str2=new String("hello");//str2指向的是堆中的地址
String str3=new String("hello");//str3指向的是堆中的地址
Object str4=new String("welcome");
System.out.println(str1==str2);
//false str1是栈中的地址 str2是堆中的地址
System.out.println(str2==str3);
//false str2是堆中的地址 str3是堆中的另一个地址 指向不同的地址(不是同一个对象) 但所包含的内容相同
System.out.println(str1=="he"+"llo");
//true 全都是字符串池中的地址
System.out.println(str1=="hel"+"lo");
//true 同上
System.out.println(str2=="hel"+"lo");
//false str2是堆中的地址
}
}
关于intern方法,对于字符串的intern方法而言,会返回一个对应字符串的标准表示。比如调用”abc”.intern(),如果字符串池中有”abc”就返回其地址,如果没有,就先将”abc”存在字符串池中,在返回其所在字符串池中的地址。
关于StringBuffer
String类型是常量,定义了之后就不可再改变了,每次用“+”的形式将两个字符串拼接起来,实际上是又生了一个新的字符串。Java中可以使用StringBuffer来对字符串进行修改,StringBuffer是一个变量,可以动态地往里面追加新的内容。利用toString方法可以将其转化成string的形式。StringBuffer buffer=new StringBuffer(“xxx”); buffer.append(xxx).apend(xxx)这里每次append之后返回的不是一个新的引用,仍然是原来的那个引用,虽然有多次append操作但是始终只有一个StringBuffer对象。