JavaRush /Java Blog /Random-TW /Java 中的等於和字串比較 - 字串比較

Java 中的等於和字串比較 - 字串比較

在 Random-TW 群組發布
你好!今天我們要講一個非常重要且有趣的話題,也就是Java中物件之間的比較equals() 。事實上,在 Java 中什麼情況下物件A等於物件B等於和字串比較 - 1讓我們試著寫一個例子:
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
控制台輸出:

false
好吧,停下來。事實上,為什麼這兩輛車不相等?我們給了它們相同的屬性,但比較的結果是錯誤的。答案很簡單。這個運算子==比較的不是物件的屬性,而是連結。即使兩個物件有 500 個相同的屬性,比較的結果仍然是 false。畢竟,連結car1指向car2 兩個不同的物件、兩個不同的地址。想像一下比較人的情況。世界上很可能有一個人和你有相同的名字、眼睛顏色、年齡、身高、頭髮顏色等。也就是說,你們在很多方面都很相似,但仍然不是雙胞胎,尤其不是同一個人。 當我們使用它來比較兩個物件時,等於和字串比較 - 2該運算子應用大致相同的邏輯。==但是如果您的程式需要不同的邏輯怎麼辦?例如,如果您的程式模擬 DNA 分析。她必須比較兩個人的 DNA 代碼並確定他們是雙胞胎。
public class Man {

   int dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
控制台輸出:

false
按邏輯,結果是一樣的(畢竟我們沒有改變任何東西),但現在我們對此不滿意!確實,在現實生活中,DNA分析百分之百保證我們面對的是雙胞胎。但我們的程式和操作員==告訴我們事實並非如此。我們怎麼能改變這種行為並確保如果 DNA 測試匹配,程式就會產生正確的結果?為此,Java 中創建了一個特殊的方法 - equals()

Java 中的 equals() 方法

與我們前面討論的方法一樣toString()equals()屬於類,ObjectJava 中最重要的類,所有其他類都派生於該類。然而,equals() 本身不會以任何方式改變我們程式的行為:
public class Man {

   String dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = "111122223333";

       Man man2 = new Man();
       man2.dnaCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
控制台輸出:

false
結果完全一樣,那為什麼需要這個方法呢?:/ 這很簡單。事實上,現在我們使用了這個方法,因為它是在類別本身中實現的Object。如果我們進入類別程式碼Object並查看該方法是如何在其中實現以及它的作用,我們將看到:
public boolean equals(Object obj) {
   return (this == obj);
}
這就是我們程式的行為沒有改變的原因!在類別的 equals() 方法中Object存在相同的參考比較==. 但這個方法的技巧是我們可以重寫它。覆蓋意味著在我們的類別中編寫您自己的 equals() 方法Man並使其按照我們想要的方式運行!現在我們不滿意該檢查man1.equals(man2)本質上與 執行相同的操作man1 == man2。在這種情況下我們會這樣做:
public class Man {

   int dnaCode;

   public boolean equals(Man man) {
       return this.dnaCode ==  man.dnaCode;
   }

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1.equals(man2));

   }
}
控制台輸出:

true
完全不同的結果!透過編寫我們自己的 equals() 方法而不是標準方法,我們實現了正確的行為:現在如果兩個人具有相同的 DNA 程式碼,程式會告訴我們:「DNA 分析表明他們是雙胞胎」並返回 true!透過重寫類別中的 equals() 方法,您可以輕鬆建立必要的物件比較邏輯。我們只是籠統地談到了物體的比較。我們接下來還會有一個關於這個主題的 單獨的大型講座(如果您有興趣,您現在可以快速閱讀)。

Java 中的字串比較 - 字串比較

為什麼我們將字串比較與其他所有內容分開處理?嗯,事實上,程式設計的台詞是一個完全不同的故事。首先,如果你拿人類寫的所有Java程式來說,其中大約25%的物件是由它們組成的。因此,這個主題非常重要。其次,比較字串的過程確實與其他物件有很大不同。讓我們來看一個簡單的例子:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
控制台輸出:

false
但為什麼是假的呢?這些行是完全相同的,逐字逐句:/您可以假設:這是因為運算子 == 比較引用!畢竟,s1它們s2在記憶體中具有不同的位址。如果你有這個想法,那麼讓我們重做我們的例子:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       System.out.println(s1 == s2);
   }
}
現在我們也有兩個鏈接,但結果卻變成了相反: 控制台輸出:

true
完全困惑嗎?:) 讓我們弄清楚。該運算子==實際上比較記憶體中的位址。這個規則總是有效的,沒有必要懷疑它。這意味著如果s1 == s2傳回 true,則這兩個字串在記憶體中具有相同的位址。確實如此!現在是時候熟悉一個用於儲存字串的特殊記憶體區域了 - 字串池 ( String pool) 等於和字串比較 - 3字串池是一個用於儲存您在程式中建立的所有字串值的區域。它是為了什麼而創建的?正如前面提到的,字串佔據了所有物件的很大一部分。在任何大型程式中,都會創建很多行。為了節省內存,這就是所需要的String Pool- 一行您需要的文本放置在那裡,以後新創建的鏈接引用相同的內存區域,無需每次分配額外的內存。每次寫入時String = “........”,程式都會檢查字串池中是否存在包含此類文字的行。如果有,則不會建立新的。並且新的連結將指向字串池中儲存該字串的相同位址。因此,當我們在程式中寫入
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
該連結s2指向與 完全相同的位置s1。第一個命令在字串池中創建了一個新行,其中包含我們需要的文本,而當執行第二個命令時,它只是引用與 相同的記憶體區域s1。您可以用相同的文字再製作至少 500 行,結果不會改變。停止。但為什麼這個例子之前對我們不起作用呢?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
我認為,憑直覺,您已經猜到原因是什麼了:) 在進一步閱讀之前嘗試猜測。您可以看到這兩行的建立方式不同。一是有操作員的幫助new,二是沒有操作員的幫助。正是這個原因。new運算子在建立物件時,會強制為其在記憶體中分配一塊新的區域。並且用 , 創建的行new不會以 結尾String Pool:它成為一個單獨的對象,即使它的文本與 'a. 中的同一行完全相同String Pool。也就是說,如果我們編寫以下程式碼:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       String s3 = new String("JavaRush is the best site to learn Java!");
   }
}
在記憶體中它看起來像這樣: 等於和字串比較 - 4每次創建一個新物件時,new都會在記憶體中分配一個新區域,即使新行內的文字是相同的!我們似乎已經解決了運算符==,但是我們的新朋友 - equals() 方法呢?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1.equals(s2));
   }
}
控制台輸出:

true
有趣的。我們確切地知道什麼s1s2指向記憶體中的不同區域。但是,儘管如此,equals() 方法表明它們是相等的。為什麼?還記得嗎,上面我們說過可以在類別中重寫 equals() 方法,以便它按照您需要的方式比較物件?這就是他們在課堂上所做的事String。它有一個重寫的 equals() 方法。它比較的不是鏈接,而是字串中的字元序列。如果字串中的文字相同,那麼它們的建立方式和儲存位置並不重要:在字串池中,還是在單獨的記憶體區域中。比較的結果將是真實的。順便說一下,Java 允許您以不區分大小寫的方式正確比較字串。正常情況下,如果你寫其中一行,例如大寫,比較的結果將為 false:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JAVARUSH - ЛУЧШИЙ САЙТ ДЛЯ ИЗУЧЕНИЯ JAVA!");
       System.out.println(s1.equals(s2));
   }
}
控制台輸出:

false
對於這種情況,該類別String有一個方法equalsIgnoreCase()。如果比較的主要內容是特定字元的序列,而不是大小寫,則可以使用它。例如,這在比較兩個電子郵件地址時非常有用:
public class Main {

   public static void main(String[] args) {

       String address1 = "Moscow, Academician Korolev street, 12";
       String address2 = new String("Г. МОСКВА, УЛ. АКАДЕМИКА КОРОЛЕВА, ДОМ 12");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
在這種情況下,很明顯我們正在談論相同的地址,因此使用方法equalsIgnoreCase()將是正確的決定。

String.intern() 方法

該類別String還有另一個棘手的方法 - intern(); 方法intern()直接與String Pool'om. intern()如果您在字串上 呼叫方法,它會:
  • 查看字串池中是否存在帶有此文字的字串
  • 如果存在,則返回池中指向它的鏈接
  • 如果沒有,它會在字串池中放置一行包含此文字的行,並傳回指向該文字的連結。
透過將該方法應用於intern()透過 new 建立的字串引用,我們可以將其與透過String Pool'a 的字串引用進行比較==
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2.intern());
   }
}
控制台輸出:

true
以前,當我們在沒有 的情況下比較它們時intern(),結果是錯誤的。現在,該方法intern()檢查是否存在包含文字「JavaRush - 學習 Java 的最佳網站!」的行。在字串池中。當然它就在那裡:我們在編寫時創建了它
String s1 = "JavaRush is the best site to learn Java!";
經過檢查,引用s1和方法返回的參考s2.intern()是否指向記憶體中的相同區域,當然,它們確實如此:) 總結一下,記住並使用主要規則:要比較字串,始終使用 equals()方法!比較字串時,幾乎總是指比較它們的文本,而不是連結、記憶體區域等。equals() 方法正是您所需要的。以下是一些連結供大家自行學習:
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION