目录
- 1.String为什么不可变
- 2.String和StringBuilder、StringBuffer的区别
- 3.String为什么要设置为不可变
- 4.判断定义为String类型的s1和s2是否相等
- 5.下面这句话在内存中创建了几个对象?
- 6.判断定义为String类型的s1和s2是否相等
- 7.判断定义为String类型的s1和s2是否相等
- 8.判断定义为String类型的s1和s2是否相等
1.String为什么不可变
什么是不可变:String不可变很简单,如下图,给一个已有字符串"abcd"第二次赋值成"abcedl",不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。
源码:
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
从注释中,可以看出value变量是String用来存放字符的,还有一个hash成员变量是该String对象的哈希值缓存。
value,hash这两个成员变量都是private final修饰的,而String类中并没有提供set/get等公共方法来修改这些值,所以String类的外部无法修改String,同时final保证了在String内部,只要值初始化了,也不能被改变。
所以认为String对象是不可变的。
而在java中,数据也是对象,那么value也仅仅是一个引用,指向真正的数组对象,这将在下面的文章中用到。
2.String和StringBuilder、StringBuffer的区别
String,StringBuffer,StringBuilder,都是final类,不允许被继承,在本质上都是字符数组,不同的是,String的长度是不可变的而后两者长度可变,在进行连接操作时,String每次返回一个新的String实例,而StringBuffer和StringBuilder的append方法直接返回this,所以当进行大量的字符串连接操作时,不推荐使用String,因为它会产生大量的中间String对象。
StringBuffer和StringBuilder的一个区别是,StringBuffer在append方法前增加了一个synchronized修饰符,以起到同步的作用,为此也降低了执行效率;若要在toString方法中使用循环,使用StringBuilder
3.String为什么要设置为不可变
(1)不可变对象可以提高String Pool(字符串常量池)的效率和安全性。如果你知道一个对象是不可变动 ,那么需要拷贝的对象的内容时就不用复制它本身二只是复制它的地址,复制地址(通常一个指针的大小)需要很小的内存,效率也很好。二对于其他引用同一个对象的其他变量也不会造成影响。
(2)可不变对象对于多线程滴安全的,因为在多线程同事进行的情况下,一个可变对象的值很可能被其他线程改变这样会造成不可预期的结果么人使用不可变对象就可以避免这种情况出现。
java将String设成不可变最大的原因是效率和安全。
不可变对象的好处
不可变对象更容易构造,测试与使用;
真正不可变对象都是线程安全的;
不可变对象的使用没有副作用(没有保护性拷贝);
对象变化的问题得到了避免;
不可变对象的失败都是原子性的;
不可变对象更容易缓存,且可以避免null引用;
不可变对象可以避免时间上的耦合;
4.判断定义为String类型的s1和s2是否相等
-
String s1 = “abc”;
-
String s2 = “abc”;
-
System.out.println(s1 == s2); //true ,比较地址值,都在常量池,相等
-
System.out.println(s1.equals(s2)); //true,equals中,先判断两个对象的地址值,地址值相同,默认就是同一个对象,不会继续equalse中的具体值是否相等的判断了,直接会返回true。
5.下面这句话在内存中创建了几个对象?
- String s1 = new String(“abc”); //两个对象 :abc在常量池,有自己的地址。 new String 创建 对象,在编译期间不能确定具体的值,所以会在 在在内存中创建的一个地址。
6.判断定义为String类型的s1和s2是否相等
-
String s1 = new String(“abc”);
-
String s2 = “abc”;
-
System.out.println(s1 == s2); //false
-
System.out.println(s1.equals(s2)); //true
7.判断定义为String类型的s1和s2是否相等
-
String s1 = “a” + “b” + “c”;
-
String s2 = “abc”;
-
System.out.println(s1 == s2); //true 地址值相同,都是常量,在常量池里面
-
System.out.println(s1.equals(s2)); //true 地址值相同,默认同一个对象,值当然也是相等的。
8.判断定义为String类型的s1和s2是否相等
-
String s1 = “ab”;
-
String s2 = “abc”;
-
String s3 = s1 + “c”;
-
System.out.println(s3 == s2); //false 不相等,s1是变量,编译的时候确定不了值,在内存中会创建值,s3在堆内存中,。s2在常量池,所以不相等。
-
System.out.println(s3.equals(s2)); //true 比较两个对象的值相等。