首先,String有两种使用方式,即作为对象来使用和基本类型来使用。
String s1 = new String(“Hello”); //作对象时,不会验证是否有相同字符串(即“Hello”),都会在堆中开辟空间存放new出来的对象,在栈中开辟一空间存放对象在堆中的地址,指向此对象。
String s2=”hi”;//作基本类型,声明时,会现在String Pool里查找有没有这个字符串,如果有直接引用指向,如果没有,则在String Pool创建一个。(之前常量池在PermGen里,java7之后放在heap(堆)中了)。
接下来说==和equals,==的意思就是都是比较是否指向堆同一个对象,这个不会变。
在Object里equals 是这样的
public boolean equals(Object obj) {
return (this == obj);
}
没错,是一样的,都是比较是否指向堆同一个对象。String类将equals方法重写
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
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;
}
即比较字符串的内容的相同与否,(其实在JavaBean里很多都会重写equals(),用来比较对象里各个值的相同与否)。
这样解释后,那么还有一个疑点,基本类型和对象之间该怎么比较
String s1 = "Hello";
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
S1指向的是StringPool里的对象,S2指向的是堆里的对象,两者并非同一个对象,但字符串相同。于是,
false
True
接下来再上几个案例便于理解。
1、
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
false
true
没有指向同一个对象,并且字符串内容相同。
2、
String s1 = new String("Hello");
String s2 = s1;
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
指向同一个对象,并且字符串内容相同。
3、
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
指向同一个对象,并且字符串内容相同。
5、
String s1 = new String("Hello");
s2 = s.intern();
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
intern()方法,工作中不常用,平常看博客偶尔会碰到,今天看了一下源码
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class <code>String</code>.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this <code>String</code> object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this <code>String</code> object is added to the
* pool and a reference to this <code>String</code> object is returned.
* <p>
* It follows that for any two strings <code>s</code> and <code>t</code>,
* <code>s.intern() == t.intern()</code> is <code>true</code>
* if and only if <code>s.equals(t)</code> is <code>true</code>.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
intern()是个native(本地)方法,简而言之就是Java中声明的可调用的使用C/C++实现的方法。Java不提供函数体,但是我们可以看注释。当intern()被调用时,会先在常量池查找有没有这个字符串对象,有就返回,没有就加进去这个字符串对象。返回的也是常量池里的字符串对象。由此可见,s1与s2皆为来自常量池的同一个字符串对象。故==与equals返回的都是true。