分析String在記憶體中的表現
建立字串的方法有兩種:
Stringstr1=”直接賦值法”
Stringstr2=new String(“通過new關鍵字的方法來建立”);
那麼這兩種建立方式有什麼區別呢?下面通過一個Demo來測試一下
- package test;
- public class Demo {
- public static void main(String[] args) {
- String str1="java";
- String str2="java";
- String str3=new String("java");
- String str4=new String("java");
- System.out.println(str1==str2); //true
- System.out.println(str1==str3); //false
- System.out.println(str3==str4); //false
- System.out.println(str3.equals(str4)); //true
- }
- }
知道了它們執行後的區別了,那麼他的原理是什麼呢?
在執行String str1=”Java”建字串的時候,jvm會首先檢查字串常量池中是否存在該字串物件,如果已經存在,那麼就不會在建立字串常量池中再建立了,直接返回該字串在字串常量池中記憶體地址,如果該字串還不存在字串常量池中,那麼就會在字串常量。池中先建立該字串的物件,然後再返回。所以在執行String str2=”java”的時候,因為字串常量池中已經存在”java”字串物件了,就不會在字串常量池中再建立了,所以在棧記憶體中str1和str2的記憶體地址都是指向”java”在字串常量池的位置。
在執行String str3=new String(“java”)建立字串的時候,jvm首先會檢查字串常量池中是否存在”java”的字串,如果已經存在,則不會在字串常量池中建立了,如果沒有存在,那麼就會在字串常量池中建立”java”字串物件,然後還會到堆記憶體中再建立一份字串物件,把字串常量池中的”java”字串內容拷貝到記憶體中的字串物件,然後返回堆記憶體中字串物件的記憶體地址。即棧記憶體儲存的地址是堆記憶體的記憶體地址。String str4=new String(“java”)是在堆記憶體中又建立了一個物件,所以str3==str4返回的是false。用一張圖來表示一下。
知道這些以後就知道前三個的輸出結果的原因了。那麼為什麼
System.out.println(str3.equals(str4));這個執行結果會返回true呢?通過看原始碼可以知道,在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 = count;
- if (n == anotherString.count) {
- char v1[] = value;
- char v2[] = anotherString.value;
- int i = offset;
- int j = anotherString.offset;
- while (n-- != 0) {
- if (v1[i++] != v2[j++])
- return false;
- }
- return true;
- }
- }
- return false;
- }
在String中的equals方法中會先判斷兩個物件的記憶體地址是否相等,如果相等,那麼equals就return true,如果不相等,則會進一步判斷傳過來的物件是不是字串型別的,如果是則將兩個字串物件char陣列,然後一個一個字元的比較,如果都相等,則返回true。
相關文章
- 記憶體屏障在CPU、JVM、JDK中的實現記憶體JVMJDK
- 分析高效記憶體池的實現方式記憶體
- 陣列在記憶體中的變化陣列記憶體
- JS中的棧記憶體、堆記憶體JS記憶體
- JAVA物件在JVM中記憶體分配Java物件JVM記憶體
- 堆外記憶體及其在 RxCache 中的使用記憶體
- 記憶體表(FDMEMTABLE)記憶體
- 記憶體分析與記憶體洩漏定位記憶體
- Ubuntu記憶體分析Ubuntu記憶體
- JVM記憶體分析JVM記憶體
- 記憶體溢位的分析記憶體溢位
- Swift記憶體賦值探索一: 理解物件在記憶體中的儲存狀態Swift記憶體賦值物件
- Node.js 中記憶體洩漏分析Node.js記憶體
- Android記憶體分析和調優(中)Android記憶體
- 關於redis記憶體分析,記憶體優化Redis記憶體優化
- GO slice 切片-在記憶體中如何分配Go記憶體
- PostgreSQL Tuple在記憶體中組織形式SQL記憶體
- 小數在記憶體中是如何儲存的?記憶體
- 【C語言】整型在記憶體中的儲存C語言記憶體
- JVM中java例項物件在記憶體中的佈局JVMJava物件記憶體
- mysql最大表記憶體MySql記憶體
- 11g記憶體管理新特性的internal表現記憶體
- SQL Server 在AlwaysOn上使用記憶體表"踩坑"SQLServer記憶體
- Oracle調優-常用表KEEP到記憶體中Oracle記憶體
- 什麼是Java記憶體模型(JMM)中的主記憶體和本地記憶體?Java記憶體模型
- leveldb原始碼分析(1)--arena記憶體池的實現原始碼記憶體
- java陣列的記憶體分析Java陣列記憶體
- 動態代理的記憶體分析記憶體
- Swoole 原始碼分析——記憶體模組之記憶體池原始碼記憶體
- 記憶體效能分析工具記憶體
- nginx共享記憶體分析Nginx記憶體
- Java 物件記憶體分析Java物件記憶體
- Go記憶體逃逸分析Go記憶體
- swoole記憶體管理分析記憶體
- Oracle記憶體全面分析Oracle記憶體
- 轉:Oracle 記憶體分析Oracle記憶體
- Java記憶體分析一Java記憶體
- 11-記憶體分析記憶體