关于 == 和 equals 使用的一些问题
问题1
StringBuffer 的 ==
和 equals
public class A {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("abc");
StringBuffer s1 = new StringBuffer("abc");
System.out.println(s1.equals(s2)); // false
System.out.println(s1==s2); // false
}
}
两个输出结果都是 false
==
比较2个对象是否占用同一个物理地址,如果是占用同一个物理地址的话,就是说这两个对象是同一个对象,返回值为 true
;如果不是占用同一个物理地址的话,就返回 false
;
StringBuffer
由于没有重写 equals
方法,所以还是使用的 Object
的 equals
方法。对比的是两个对象的地址是否相等,等同 ==
StringBuilder
与 StringBuffer
一样
问题2
String
的 ==
和 equals
=
直接创建的 String
字符串存储在公共池中,而 new
创建的字符串对象在堆上
String s1 = "hello"; // String 直接创建
String s2 = "hello"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("hello"); // String 对象创建
String s5 = new String("hello"); // String 对象创建
直接使用
String
:对于储存在常量池中的字符串常量,在
String
对象和引用绑定时,JVM
在运行时,会先在常量池查找是否存在相同的字面常量;
如果存在,则直接将引用指向已经存在的字面常量;否则,在运行时,常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量使用
new
:通过
new
关键字来生成对象是在堆区进行的,而在堆区进行对象生成时,不会检测该对象是否存在
因此,通过new
来创建对象,创建出的一定是不同的对象,即使字符串的内容是一样的
重点:
==
比较的是两个对象的地址值,对于分别处于常量池和堆中的字符串,一定不等
String
类中重写了 equals()
方法用于比较两个字符串的内容是否相等
equals()
比较的是字面值,对于分别处于常量池和堆中的字符串,可以相等
String s1 = "Hello"; // String 直接创建
String s2 = "Hello"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Hello"); // String 对象创建
String s5 = new String("Hello"); // String 对象创建
s1 == s1; // true, 相同引用
s1 == s2; // true, s1 和 s2 都在公共池中,引用相同
s1 == s3; // true, s3 与 s1 引用相同
s1 == s4; // false, 不同引用地址
s4 == s5; // false, 堆中不同引用地址
s1.equals(s3); // true, 相同内容
s1.equals(s4); // true, 相同内容
s4.equals(s5); // true, 相同内容
问题3
concat()
和 +
的区别
pubic class Demo{
pulic satic void main(String[] args){
String str1 = "a".concat("b").concat("c");
String str2 = "a"+"b"+"c";
String str3 = "abc";
String str4 = new String("abc");
System.out.println(str1 == str2); //运行结果为false
System.out.println(str1 == str3); //运行结果为false
System.out.println(str2 == str3); //运行结果为ture
System.out.println(str2 == str4); //运行结果为false
System.out.println(str1.equals(str4)); //运行结果为true
}
}
==
比较的是两个对象的地址值,equals()
比较的是字面值
那么 concat()
方法和 +
号的区别在这里有体现了,查看 concat
方法的源码可以看到,它是先复制数组,再通过 char
数组进行拼接生成一个新的对象,所以地址值会有变动,而 +
号不会
问题4
intern()
返回字符串对象的规范化表示形式。
- 对于任意两个字符串
s
和t
,当且仅当s.equals(t)
为true
时,s.intern()==t.intern()
才为true
public class Test {
public static void main(String args[]) {
String Str1 = new String("hello");
String Str2 = new String("HELLO");
System.out.println("规范表示:" );
System.out.println(Str1.intern()); // hello
System.out.println(Str2.intern()); // HELLO
System.out.println("深入研究");
String str1 = "a";
String str2 = "b";
String str3 = "ab";
tring str4 = str1 + str2;
tring str5 = new String("ab");
System.out.println(str5.equals(str3)); // true
System.out.println(str5 == str3); // false
System.out.println(str5.intern() == str3); // true
System.out.println(str5.intern() == str4); // false
}
}
-
str5.equals(str3)
这个结果为true
,不用太多的解释,因为字符串的值的内容相同。 -
str5 == str3
对比的是引用的地址是否相同,由于str5
采用new String
方式定义的,所以地址引用一定不相等。所以结果为false
。 -
当
str5
调用intern
的时候,会检查字符串池中是否含有该字符串。由于之前定义的str3
已经进入字符串池中,所以会得到相同的引用。 -
当
str4 = str1 + str2
后,str4
的值也为”ab”
,但是因为是变量相加,所以不会进入字符串池
对于第四个结果,可以通过代码展示原因
String a = new String("ab");
String b = new String("ab");
String c = "ab";
String d = "a" + "b";
String e = "b";
String f = "a" + e;
System.out.println(b.intern() == a); // false
System.out.println(b.intern() == c); // true
System.out.println(b.intern() == d); // true
System.out.println(b.intern() == f); // false
System.out.println(b.intern() == a.intern()); // true
由运行结果可以看出来,b.intern() == a
和 b.intern() == c
可知,采用 new
创建的字符串对象不进入字符串池
通过 b.intern() == d
和 b.intern() == f
可知,字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如 f
中的 e
)则不会进入字符串池中。
但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象。
String a = "abc";
String b = "abc";
String c = "a" + "b" + "c";
String d = "a" + "bc";
String e = "ab" + "c";
// 以下结果均为 true
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a == d);
System.out.println(a == e);
System.out.println(c == d);
System.out.println(c == e);
如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用。
- 点赞
- 收藏
- 关注作者
评论(0)