CodeGym /Blog Java /rawak /Bandingkan perbandingan String dan Equals dalam Java
John Squirrels
Tahap
San Francisco

Bandingkan perbandingan String dan Equals dalam Java

Diterbitkan dalam kumpulan
Hai! Hari ini kita akan bercakap tentang topik yang sangat penting dan menarik, iaitu membandingkan objek dengan objek (Bandingkan Strings dan Equals). Jadi di Jawa, bilakah sebenarnya objek A sama dengan objek B ? Mari cuba menulis contoh:

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);
   }
}
Output konsol: palsu Tunggu, berhenti. Kenapa kedua-dua kereta ini tidak sama? Kami memberikan mereka sifat yang sama, tetapi hasil perbandingan adalah palsu. Jawapannya mudah sahaja. Operator == membandingkan rujukan objek, bukan sifat objek. Dua objek juga boleh mempunyai 500 medan dengan nilai yang sama, tetapi membandingkannya masih akan menghasilkan palsu. Lagipun, rujukan kereta1 dan kereta2tunjuk kepada dua objek berbeza, iaitu dua alamat berbeza. Bayangkan situasi di mana anda membandingkan orang. Sudah tentu, di suatu tempat di dunia terdapat seseorang yang berkongsi nama anda yang sama, warna mata, umur, ketinggian, warna rambut, dll. Itu menjadikan anda serupa dalam banyak aspek, tetapi anda masih bukan kembar — dan anda jelas bukan orang yang sama.
Perbandingan sama dan rentetan - 2
Operator == menggunakan kira-kira logik yang sama apabila kita menggunakannya untuk membandingkan dua objek. Tetapi bagaimana jika anda memerlukan program anda untuk menggunakan logik yang berbeza? Sebagai contoh, katakan program anda menjalankan analisis DNA. Ia membandingkan kod genetik dua orang, dan menentukan sama ada mereka kembar.

public class Man {

   int geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1 == man2);
   }
}
Output konsol: false Kami mendapat hasil logik yang sama (kerana kami tidak banyak berubah), tetapi sekarang logik itu tidak bagus! Lagipun, dalam kehidupan sebenar, analisis DNA sepatutnya memberi kita jaminan 100% bahawa kita mempunyai kembar berdiri di hadapan kita. Tetapi program kami dan operator == memberitahu kami sebaliknya. Bagaimanakah kita mengubah tingkah laku ini dan memastikan program mengeluarkan hasil yang betul apabila DNA sepadan? Java mempunyai kaedah khas untuk ini: equals() . Seperti kaedah toString() , yang kita bincangkan sebelum ini, equals() tergolong dalam kelas Object — kelas yang paling penting dalam Java, kelas dari mana semua kelas lain diperolehi. Tetapi sama dengan()tidak mengubah tingkah laku program kami dengan sendirinya:

public class Man {

   String geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1.equals(man2));
   }
}
Output konsol: palsu Hasil yang sama persis, jadi untuk apa kita memerlukan kaedah ini? :/ Semuanya mudah. Isu di sini ialah kami sedang menggunakan kaedah ini kerana ia dilaksanakan dalam kelas Objek . Dan jika kita pergi ke kod kelas Objek dan melihat pelaksanaan kaedah, inilah yang akan kita lihat:

public boolean equals(Object obj) {
   return (this == obj);
}
Itulah sebab mengapa tingkah laku program tidak berubah! Operator == yang sama (yang membandingkan rujukan) digunakan dalam kaedah equals() kelas Objek . Tetapi helah dengan kaedah ini ialah kita boleh mengatasinya. Untuk mengatasi bermaksud menulis kaedah equals() anda sendiri dalam kelas Man kami , memberikannya tingkah laku yang kami perlukan! Pada masa ini, kami tidak menyukai hakikat bahawa man1.equals(man2) pada asasnya bersamaan dengan man1 == man2 . Inilah yang akan kami lakukan dalam situasi ini:

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)); 

   } 
} 
Output konsol: benar Kini kami mendapat hasil yang sama sekali berbeza! Dengan menulis kaedah equals() kami sendiri dan menggunakannya dan bukannya kaedah standard, kami telah menghasilkan tingkah laku yang betul: Sekarang jika dua orang mempunyai DNA yang sama, program melaporkan "Analisis DNA telah membuktikan mereka adalah kembar" dan kembali benar! Dengan mengatasi kaedah equals() dalam kelas anda, anda boleh membuat apa sahaja logik perbandingan objek yang anda perlukan dengan mudah. Sebenarnya, kami baru sahaja menyentuh tentang perbandingan objek. Di hadapan kita, masih terdapat pelajaran kendiri yang besar tentang topik ini (anda membacanya sekarang jika anda berminat).

Membandingkan rentetan dalam Java

Mengapa kita mempertimbangkan perbandingan rentetan secara berasingan daripada yang lain? Realitinya ialah rentetan adalah subjek dalam pengaturcaraan mereka sendiri. Pertama, jika anda mengambil semua program Java yang pernah ditulis, anda akan mendapati bahawa kira-kira 25% daripada objek di dalamnya adalah rentetan. Jadi topik ini sangat penting. Kedua, proses membandingkan rentetan adalah sangat berbeza daripada objek lain. Pertimbangkan contoh mudah:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Output konsol: palsu Tetapi mengapa kami mendapat palsu? Lagipun, rentetannya betul-betul sama, perkataan demi perkataan :/ Anda mungkin telah meneka sebabnya: ini kerana operator == membandingkan rujukan ! Jelas sekali, s1 dan s2 mempunyai alamat yang berbeza dalam ingatan. Jika anda memikirkannya, mari kita susun semula contoh kita:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
Sekarang kita sekali lagi mempunyai dua rujukan, tetapi hasilnya adalah sebaliknya: Output konsol: benar Tidak berdaya keliru? Mari kita fikirkan apa yang berlaku. Operator == benar-benar membandingkan alamat memori. Ini sentiasa benar dan anda tidak perlu meraguinya. Ini bermakna jika s1 == s2 kembali benar, maka kedua-dua rentetan ini mempunyai alamat yang sama. Dan sesungguhnya ini benar! Sudah tiba masanya untuk memperkenalkan anda kepada kawasan memori khas untuk menyimpan rentetan: kolam rentetan
Perbandingan sama dan rentetan - 3
Kolam rentetan ialah kawasan untuk menyimpan semua nilai rentetan yang anda buat dalam program anda. Mengapa ia dicipta? Seperti yang kami katakan sebelum ini, rentetan mewakili peratusan yang besar daripada semua objek. Mana-mana program besar mencipta banyak rentetan. Kolam rentetan dicipta untuk menyimpan memori: rentetan diletakkan di sana dan kemudian rentetan dicipta merujuk kepada kawasan memori yang sama—tidak perlu memperuntukkan memori tambahan setiap kali. Setiap kali anda menulis String = "........" program menyemak sama ada terdapat rentetan yang sama dalam kolam rentetan. Jika ada, maka rentetan baharu tidak akan dibuat. Dan rujukan baharu akan menunjuk ke alamat yang sama dalam kolam rentetan (di mana rentetan yang sama terletak). Jadi apabila kita menulis

String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 menunjuk ke tempat yang sama dengan s1 . Pernyataan pertama mencipta rentetan baharu dalam kolam rentetan. Pernyataan kedua hanya merujuk kepada kawasan ingatan yang sama seperti s1 . Anda boleh membuat 500 lagi rentetan yang sama dan hasilnya tidak akan berubah. Tunggu sekejap. Jika itu benar, maka mengapa contoh ini tidak berfungsi sebelum ini?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Saya rasa intuisi anda telah memberitahu anda sebabnya =) Cuba teka sebelum membaca lebih lanjut. Anda boleh melihat bahawa kedua-dua rentetan ini diisytiharkan dengan cara yang berbeza. Satu dengan pengendali baharu, dan satu lagi tanpanya. Di sinilah letak sebabnya. Apabila pengendali baharu digunakan untuk mencipta objek, ia memperuntukkan kawasan memori baharu secara paksa untuk objek tersebut. Dan rentetan yang dibuat menggunakan baharu tidak berakhir dalam kolam rentetan — ia menjadi objek yang berasingan, walaupun teksnya sepadan dengan sempurna dengan rentetan dalam kolam rentetan. Iaitu, jika kita menulis kod berikut:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
Dalam ingatan, ia kelihatan seperti ini:
Perbandingan sama dan rentetan - 4
Dan setiap kali anda mencipta objek baharu menggunakan new , kawasan memori baharu diperuntukkan, walaupun teks di dalam rentetan baharu adalah sama! Nampaknya kita telah mengetahui operator == . Tetapi bagaimana dengan kenalan baru kami, kaedah equals() ?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
Output konsol: benar Menarik. Kami pasti bahawa s1 dan s2 menunjuk ke kawasan yang berbeza dalam ingatan. Tetapi kaedah equals() masih memberitahu kami bahawa mereka adalah sama. kenapa? Ingat kita sebelum ini mengatakan bahawa kaedah equals() boleh ditindih untuk membandingkan objek walau bagaimanapun kita mahu? Itu sahaja yang mereka lakukan dengan kelas String . Ia mengatasi sama dengan()kaedah. Dan bukannya membandingkan rujukan, ia membandingkan jujukan aksara dalam rentetan. Jika teks adalah sama, maka tidak kira bagaimana ia dicipta atau di mana ia disimpan: sama ada dalam kolam rentetan atau kawasan memori yang berasingan. Hasil perbandingan akan menjadi benar. Dengan cara ini, Java membolehkan anda melakukan perbandingan rentetan tidak sensitif huruf besar-besaran. Biasanya, jika salah satu rentetan mempunyai semua huruf besar, maka hasil perbandingan adalah palsu:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Output konsol: palsu Untuk perbandingan tidak peka huruf besar-besaran, kelas String mempunyai kaedah equalsIgnoreCase() . Anda boleh menggunakannya jika anda hanya mengambil berat tentang membandingkan jujukan aksara tertentu dan bukannya huruf besar. Sebagai contoh, ini boleh membantu apabila membandingkan dua alamat:

public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
Dalam kes ini, kami jelas bercakap tentang alamat yang sama, jadi masuk akal untuk menggunakan kaedah equalsIgnoreCase() .

Kaedah String.intern().

Kelas String mempunyai satu lagi kaedah rumit: intern() ; Kaedah intern() berfungsi secara langsung dengan kolam rentetan. Jika anda memanggil kaedah intern() pada beberapa rentetan:
  • Ia menyemak sama ada terdapat rentetan yang sepadan dalam kolam rentetan
  • Jika ada, ia mengembalikan rujukan kepada rentetan dalam kolam
  • Jika tidak, ia menambah rentetan pada kolam rentetan dan mengembalikan rujukan kepadanya.
Selepas menggunakan kaedah intern() pada rujukan rentetan yang diperoleh menggunakan new , kita boleh menggunakan operator == untuk membandingkannya dengan rujukan rentetan daripada kolam rentetan.

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
Output konsol: true Apabila kami membandingkan rentetan ini sebelum ini tanpa intern() , hasilnya adalah palsu. Kini kaedah intern() menyemak sama ada rentetan "CodeGym ialah tapak terbaik untuk mempelajari Java!" berada dalam kolam rentetan. Sudah tentu, ia adalah: kami menciptanya dengan

String s1 = "CodeGym is the best website for learning Java!";
Kami menyemak sama ada s1 dan rujukan yang dikembalikan oleh s2.intern() menghala ke kawasan memori yang sama. Dan sudah tentu, mereka melakukannya :) Secara ringkasnya, hafal dan gunakan peraturan penting ini: SENTIASA gunakan kaedah equals() untuk membandingkan rentetan! Apabila membandingkan rentetan, kami hampir selalu bermaksud untuk membandingkan watak mereka dan bukannya rujukan, kawasan ingatan atau apa-apa lagi. Kaedah equals() melakukan apa yang anda perlukan. Untuk mengukuhkan perkara yang anda pelajari, kami cadangkan anda menonton pelajaran video daripada Kursus Java kami

Bacaan lanjut:

Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION