String str1 和 str2 所指向的對象在字元串常量池中,是同一個對象。 All literal strings and string valued constant expressions are interned,When the intern method is invoked, i ...
String
//string intern pool
String str1 = "a";
String str2 = "a";
System.out.println(str1.equals(str2));//true
System.out.println(str1==str2);//true
System.out.println(str1.hashCode());//97
System.out.println(str2.hashCode());//97
str1 和 str2 所指向的對象在字元串常量池中,是同一個對象。
All literal strings and string-valued constant expressions are interned,When the intern method is invoked, if the pool already contains a string equal to this {@code String} object as determined by the {@link #equals(Object)} method, then the string from the pool is returned.
String.intern()方法的註釋:
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
* <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.
* @jls 3.10.5 String Literals
*/
public native String intern();
String str3 = "a";//string intern pool,constant pool
String str4 = new String("a");//heap object
System.out.println(str3.equals(str4));//true
System.out.println(str3==str4);//false
- str3所指向的對象在常量池中,str4所指向的對象分配在堆上,== 基於對象的地址來判斷,因此返回false
String str5 = "a";
String str6 = String.valueOf("a");//string intern pool, constant pool
System.out.println(str5.equals(str6));//true
System.out.println(str5 == str6);//true
看String.valueOf的源碼如下:
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
參數 obj 是 "a",也即是一個字元串對象,再看String.toString()方法源碼如下:返回的是this 對象本身。因此,
System.out.println(str5 == str6);
輸出true/** * This object (which is already a string!) is itself returned. * * @return the string itself. */ public String toString() { return this; }
Integer
Integer integer1 = new Integer(1);// heap obj
Integer integer2 = new Integer(1);//another heap obj
System.out.println(integer1.equals(integer2));//true
System.out.println(integer1 == integer2);//false
採用關鍵字 new 創建對象,integer1 和 integer2 是堆上兩個不同的對象,因此
System.out.println(integer1 == integer2)
輸出falseJDK9已經不推薦使用 new 來創建 Integer對象,因為new沒有使用緩存,有性能問題。
/** * Constructs a newly allocated {@code Integer} object that * represents the specified {@code int} value. * * @param value the value to be represented by the * {@code Integer} object. * * @deprecated * It is rarely appropriate to use this constructor. The static factory * {@link #valueOf(int)} is generally a better choice, as it is * likely to yield significantly better space and time performance. */ @Deprecated(since="9") public Integer(int value) { this.value = value; }
Integer integer3 = 1;
Integer integer4 = 1;
System.out.println(integer3.equals(integer4));//true
System.out.println(integer3==integer4);//true
包裝類Integer對範圍-128~127之間的數據進行了緩存。直接賦值方式使得:integer3 和 integer4 指向的是同一個對象。
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * jdk.internal.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[];
Integer integer5 = 128;
Integer integer6 = 128;
System.out.println(integer5.equals(integer6));//true
System.out.println(integer5 == integer6);//false
- 128 超過了預設的緩存範圍,因此
System.out.println(integer5 == integer6)
輸出false
Integer integer7 = 127;
Integer integer8 = Integer.valueOf(127);
System.out.println(integer7.equals(integer8));//true
System.out.println(integer7 == integer8);//true
127在緩存範圍之內,Integer.valueOf()方法返回的是緩存的對象,因此 integer7 和 integer8 指向的是同一個對象,故
System.out.println(integer7 == integer8)
輸出trueInteger.valueOf源碼如下:
/** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link #Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ @HotSpotIntrinsicCandidate public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
Integer integer9 = 128;
Integer integer10 = Integer.valueOf(128);
System.out.println(integer9.equals(integer10));//true
System.out.println(integer9 == integer10);//false
- 128超過了預設緩存範圍,因此
System.out.println(integer9 == integer10)
輸出false
寫了這麼多並不是說要記住每種情況,而是要瞭解以下幾個點:
- String 字元串常量池,字面量都存儲在常量池中。
- == 比較 與equals比較區別。
- equals比較與hashCode方法的聯繫。如果兩個對象equals返回true,那麼這兩個對象的hashCode肯定是相同的;如果兩個對象的equals返回false,兩個對象的hashCode可以是相同的,hashCode相同意味著發生了衝突,就是常討論的HashMap 的Key 衝突的情形。
- 基本數據類型有對應的包裝類,包裝類有數據緩存的功能,用對了地方能提升性能。
- 明白 = 賦值創建對象 和 new 創建對象的區別,new一個對象時,對象會分配在堆中。
- 瞭解JDK基礎類的常用方法的底層實現源碼
完整代碼:
public class StringIntegerCompare {
public static void main(String[] args) {
//string intern pool
String str1 = "a";
String str2 = "a";
System.out.println(str1.equals(str2));//true
System.out.println(str1==str2);//true
System.out.println(str1.hashCode());//97
System.out.println(str2.hashCode());//97
String str3 = "a";//string intern pool,constant pool
String str4 = new String("a");//heap object
System.out.println(str3.equals(str4));//true
System.out.println(str3==str4);//false
System.out.println(str3.hashCode());//true
System.out.println(str4.hashCode());//true
String str5 = "a";
String str6 = String.valueOf("a");//string intern pool, constant pool
System.out.println(str5.equals(str6));//true
System.out.println(str5 == str6);//true
System.out.println(str5.hashCode());//97
System.out.println(str6.hashCode());//97
String str7 = new String("b");//string object on heap
String str8 = String.valueOf(str7);
System.out.println(str7.equals(str8));//true
System.out.println(str7 == str8);//true
System.out.println(str7.hashCode());
System.out.println(str8.hashCode());
System.out.println("-----------------------");
Integer integer1 = new Integer(1);// heap obj
Integer integer2 = new Integer(1);//another heap obj
System.out.println(integer1.equals(integer2));//true
System.out.println(integer1 == integer2);//false
System.out.println(integer1.hashCode());//1
System.out.println(integer2.hashCode());//1
Integer integer3 = 1;
Integer integer4 = 1;
System.out.println(integer3.equals(integer4));//true
System.out.println(integer3==integer4);//true
System.out.println(integer3.hashCode());//1
System.out.println(integer4.hashCode());//1
Integer integer5 = 128;
Integer integer6 = 128;
System.out.println(integer5.equals(integer6));//true
System.out.println(integer5 == integer6);//false
System.out.println(integer5.hashCode());//128
System.out.println(integer6.hashCode());//128
Integer integer7 = 127;
Integer integer8 = Integer.valueOf(127);
System.out.println(integer7.equals(integer8));//true
System.out.println(integer7 == integer8);//true
Integer integer9 = 128;
Integer integer10 = Integer.valueOf(128);
System.out.println(integer9.equals(integer10));//true
System.out.println(integer9 == integer10);//false
}
}
JDK版本:
panda@panda-e550:~$ java -version
java version "10.0.2" 2018-07-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.2+13)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.2+13, mixed mode)
原文:https://www.cnblogs.com/hapjin/p/10067875.html