字符串类型是常用的数据类型,但是其特殊性是字符串是在堆中创建的。在jvm中有一个String Pool(字符串池),用来缓存字符串。
在字符串中有两种赋值方式:
(1)String s=“aaa”;
①首先查找String Pool中是否存在"aaa"这个对象,如果不存在,如果不存在,就会在String Pool创建一个一个“aaa”的对象,然后将池中的“aaa”对象的地址返回,赋值给s这个引用变量
②如果存在,不创建任何对象,将“aaa”的地址返回给s引用。
(2)String str=new String(“aaa”);
①首先在String Pool查找有没有“aaa”这个字符串对象,如果有,就不会在String Pool创建,在堆中创建一个对象,然后将堆中的地址返回引用str,
②如果没有,先在String Pool中创建一个“aaa”对象,然后在堆中(heap)创建一个对象,然后将堆中的地址传回来。
对于字符串的这种特性,我觉得是很好的一个面试点,比如下面的代码
//请问一共有多少个对像
String a = new String("1");
String b= new String("1");
这个是有三个对象的,首先a先会在字符池中创建一个值为1的对象,然后继续会在堆区域创建一个值为1的对象,在第二个new的时候首先会在字符池中去找有1没有,有的话就不会创建,然后在再在堆区域创建一个对象。
equals()方法
该方法定义在Object类中,因此java中的每一个类都具有该方法,对于Object类的equals()方法来说,他是判断equals()方法的引用于传进来的引用是否一致,及这两个引用是否指向同一个对象。
对于String类的equals()方法来说,他是判断当前字符串与传进来的字符串是否一致,
对于String对象的相等性,使用equals方法,而不是==。
对于object类的equals()方法,是判断地址是否相等,而对于String中继承了Object的equals()是比较内容是否相等。
public class StringTest
{
public static void main(String []args) {
String str=new String("aa");
String str2=new String("aa");
System.out.println(str.equals(str2));
String str3="aa";
String str4="aa";
System.out.println(str3.equals(str4));
Object object=new Object();
Object object2=new Object();
System.out.println(object.equals(object2));
}
}
答案是这样的:
空串与null串
空串是一个java对象,有自己的长度为0和内容为空,但是null表示目前没有任何对象与该变量关联。
String、StringBuilder、StringBuffer
字符串相关类型主要有三种String、StringBuilder、StringBuffer。String是只读字符串,对他的任何改动都会创建一个新的对象,再把引用指向该对象。String对象赋值操作后,会在常量池进行缓存,下次申请的时候,如果缓存中已经存在,则直接返回相应引用给创建者。StringBuffer可以在原对象上进行修改,线程是安全的,(我去看了一下源码,发现每个方法都是加了锁的)。StringBuilder是非线程安全的,把加锁的位置交给了工程师决定,操作效率比StringBuffer高。
接下来我们来看一段代码
String str="start";
for(int i = 0;i<100; i++){
str=str+"hello";
}
这段代码的内部实现逻辑是每次循环都会new一个StringBuilder对象,然后进行append操作,最后通过toString方法来返回String对象,浪费资源并且性能差,我们一般在进行循环的时候应该使用StringBuilder的append方法而不是直接相加。