ฉันจะเปรียบเทียบสตริงใน Java ได้อย่างไร


724

ฉันใช้==โอเปอเรเตอร์ในโปรแกรมของฉันเพื่อเปรียบเทียบสตริงทั้งหมดของฉันจนถึงตอนนี้ อย่างไรก็ตามฉันพบข้อผิดพลาดเปลี่ยนหนึ่งในนั้น.equals()แทนและแก้ไขข้อผิดพลาด

คือ==ไม่ดี? เมื่อใดควรและไม่ควรใช้ ความแตกต่างคืออะไร?


12
นอกจากนี้ยังเป็นการดีที่จะรู้ว่าหากคุณใช้วิธีการ. แทนที่ () วิธีการทำให้แน่ใจว่าคุณกำลังแทนที่. hashcode () วิธีการมิฉะนั้นคุณจะสิ้นสุดด้วยการละเมิดความสัมพันธ์เทียบเท่า b / w เท่ากับและ hashcode สำหรับข้อมูลเพิ่มเติมอ้างอิง java doc
Nageswaran

ออกจากลิงก์ไปยังคำอธิบายของฉันเกี่ยวกับสาเหตุที่==ทำงานบน Objects: stackoverflow.com/a/19966154/2284641
Johannes H.

==จะทำงานบางครั้งเนื่องจาก java มี String pool ซึ่งจะพยายามใช้การอ้างอิงหน่วยความจำของสตริงที่ใช้บ่อย แต่==เปรียบเทียบว่าวัตถุมีค่าเท่ากันไม่ใช่ค่า ... ดังนั้นจึง.equals()เป็นการใช้งานที่เหมาะสมที่คุณต้องการใช้
James Oravec

อย่าใช้ == เพื่อทดสอบว่า Strings เหมือนกันหรือไม่เว้นแต่คุณจะสนุกกับการติดตามข้อผิดพลาดเล็กน้อยและศึกษาความซับซ้อนของกระบวนการฝึกงานของ Java String "12"=="1"+2เป็นเท็จ (อาจ)
เที่ยวบินโอดิสซีย์

คำตอบ:


5560

== ทดสอบความเท่าเทียมกันอ้างอิง (ไม่ว่าจะเป็นวัตถุเดียวกัน)

.equals() ทดสอบความเท่าเทียมกันของค่า (ไม่ว่าพวกเขาจะมีเหตุผล "เท่าเทียมกัน")

Objects.equals ()ตรวจสอบnullก่อนโทร.equals()ดังนั้นคุณจึงไม่จำเป็นต้อง (มีให้ตั้งแต่ JDK7 และมีให้ในGuava ด้วย )

Objects.equals()ดังนั้นหากคุณต้องการที่จะทดสอบว่าสองสายมีค่าเดียวกันที่คุณอาจจะต้องการใช้งาน

// These two have the same value
new String("test").equals("test") // --> true 

// ... but they are not the same object
new String("test") == "test" // --> false 

// ... neither are these
new String("test") == new String("test") // --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" // --> true 

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

คุณเกือบจะเสมอObjects.equals()ต้องการที่จะใช้ ในที่หายากสถานการณ์ที่คุณรู้ว่าคุณอยู่กับการซื้อขายฝึกงานสตริงคุณสามารถ==ใช้

จากJLS 3.10.5 ตัวอักษรสตริง :

นอกจากนี้ตัวอักษรสตริงเสมอหมายถึงเดียวกันStringตัวอย่างของการเรียน นี้เป็นเพราะตัวอักษรของสตริง - หรืออื่น ๆ โดยทั่วไปสตริงที่มีค่าของการแสดงออกอย่างต่อเนื่อง ( §15.28 ) - เป็น "ฝึกงาน" String.internเพื่อให้เป็นไปหุ้นกรณีที่ไม่ซ้ำกันโดยใช้วิธีการ

ตัวอย่างที่คล้ายกันนอกจากนี้ยังสามารถพบได้ในJLS 3.10.5-1

วิธีการอื่นที่ควรพิจารณา

String.equalsIgnoreCase ()ค่าความเท่าเทียมกันที่ไม่สนใจตัวพิมพ์

String.contentEquals ()เปรียบเทียบเนื้อหาของStringกับเนื้อหาของใด ๆCharSequence(ใช้ได้ตั้งแต่ Java 1.5) ช่วยให้คุณไม่ต้องเปลี่ยน StringBuffer ของคุณ ฯลฯ เป็น String ก่อนทำการเปรียบเทียบความเท่าเทียมกัน


3
หาก == ตรวจสอบความเท่าเทียมกันของข้อมูลอ้างอิงเหตุใด n == 5 จึงสมเหตุสมผล 5 ไม่ใช่ตัวแปร
Hrit Roy

2
@HritRoy เพราะ==ตรวจสอบค่าของตัวแปร เมื่อคุณมีวัตถุตัวแปรที่อ้างอิงวัตถุมีการอ้างอิงของวัตถุเป็นมูลค่า ดังนั้นคุณเปรียบเทียบอ้างอิง==เมื่อเปรียบเทียบกับสองตัวแปร เมื่อเปรียบเทียบประเภทข้อมูลดั้งเดิมเช่นintมันยังคงเป็นกรณีเดียวกัน ตัวแปรชนิดintมีจำนวนเต็มเป็นค่า ดังนั้นคุณเปรียบเทียบค่าของทั้งสองints ==ใช้ หากintเป็นค่าของตัวแปรหรือหมายเลขมายากลไม่สำคัญ นอกจากนี้:การอ้างอิงคืออะไรนอกจากตัวเลขที่อ้างถึงหน่วยความจำ
akuzminykh

718

==ทดสอบการอ้างอิงวัตถุ.equals()ทดสอบค่าสตริง

บางครั้งดูเหมือนว่า==เปรียบเทียบค่าเพราะ Java ทำบางสิ่งเบื้องหลังเพื่อให้แน่ใจว่าสตริงในบรรทัดเหมือนกันจริง ๆ แล้วเป็นวัตถุเดียวกัน

ตัวอย่างเช่น:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

แต่ระวังโมฆะ!

==จัดการกับnullสตริงได้ดี แต่การโทร.equals()จากสตริง null จะทำให้เกิดข้อยกเว้น:

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

ดังนั้นถ้าคุณรู้ว่าfooString1อาจเป็นโมฆะบอกผู้อ่านด้วยการเขียน

System.out.print(fooString1 != null && fooString1.equals("bar"));

ต่อไปนี้สั้นกว่า แต่ก็ไม่ค่อยชัดเจนว่าจะตรวจสอบค่าว่าง:

System.out.print("bar".equals(fooString1));  // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar"));  // Java 7 required

86
บางครั้งดูเหมือนว่า "==" เปรียบเทียบค่า - == อย่าเปรียบเทียบค่าเสมอ! (เป็นเพียงค่าที่แน่นอนคือการอ้างอิง!)
aioobe

6
อนิจจาไม่มีวิธีแบบคงที่สำหรับ isNullOrEmpty () และไม่มีการบรรทุกเกินพิกัดที่กำหนดเองของผู้ประกอบการซึ่งทำให้ส่วนนี้ของ clunkier Java กว่าใน C # หรือ Python และเนื่องจาก Java ไม่มีวิธีการขยายคุณจึงไม่สามารถเขียนโปรแกรมอรรถประโยชน์ของคุณเองเพื่อขยาย java.lang.String ขวา? มีความคิดเห็นเกี่ยวกับ Subclassing String เพิ่มวิธียูทิลิตี้สแตติกนั้นแล้วใช้ MyString แทนเสมอหรือไม่ เมธอดแบบสแตติกที่มีพารามิเตอร์สองตัวสำหรับทำการเปรียบเทียบที่ปลอดภัยและไม่มีค่าควรจะดีในคลาสย่อยนั้นเช่นกัน
Jon Coombs

7
Groovy ทำให้นี้ง่ายขึ้นเล็ก ๆ น้อย ๆ กับผู้ประกอบการนำทางที่ปลอดภัย ( groovy.codehaus.org/...?. ) ที่จะแปลงnullString1?.equals(nullString2);เป็นคำสั่งที่ว่างเปล่าทั้งหมด อย่างไรก็ตามมันไม่ช่วยถ้าคุณมีvalidString?.equals(nullString);- ที่ยังคงมีข้อยกเว้น
Charles Wood

5
วิธีการสั้น ๆ เพื่อเปรียบเทียบสตริงที่ไม่สามารถใช้งานได้ใน java: stackoverflow.com/questions/11271554/…
Vadzim

5
@JonCoombs Java รองรับคลาสย่อยและสร้างวิธีการของตัวเอง อย่างไรก็ตามมีเพียงไม่กี่คลาสที่ถูกทำเครื่องหมายสุดท้ายเนื่องจากเหตุผลบางอย่างสตริงเป็นหนึ่งในนั้นดังนั้นเราจึงไม่สามารถขยายได้ เราสามารถสร้างคลาสอื่นและสร้างคลาสยูทิลิตี้ที่มีสองสตริงเป็นอาร์กิวเมนต์และใช้ตรรกะของเราที่นั่น นอกจากนี้สำหรับ null ให้ตรวจสอบไลบรารี่อื่น ๆ เช่น spring และ apache เขาสามารถใช้วิธีการเหล่านี้ได้
Panther

442

== เปรียบเทียบการอ้างอิงวัตถุ

.equals() เปรียบเทียบค่าสตริง

บางครั้ง==ให้ภาพลวงตาของการเปรียบเทียบค่าสตริงเช่นในกรณีต่อไปนี้:

String a="Test";
String b="Test";
if(a==b) ===> true

นี่เป็นเพราะเมื่อคุณสร้างสัญพจน์ String ใด ๆ JVM จะค้นหาสัญพจน์นั้นในพูพูล String ก่อนและหากพบการจับคู่การอ้างอิงเดียวกันนั้นจะถูกกำหนดให้กับสตริงใหม่ ด้วยเหตุนี้เราได้รับ:

(a == b) ===> จริง

                       String Pool
     b -----------------> "test" <-----------------a

อย่างไรก็ตาม==ล้มเหลวในกรณีต่อไปนี้:

String a="test";
String b=new String("test");
if (a==b) ===> false

ในกรณีนี้สำหรับnew String("test")คำสั่ง String ใหม่จะถูกสร้างขึ้นบนฮีปและการอ้างอิงนั้นจะมอบให้bดังนั้นbจะได้รับการอ้างอิงบนฮีปไม่ใช่ในพูลพูลของสตริง

ตอนนี้aชี้ไปที่ String ใน Pool String ขณะที่bชี้ไปที่ String บนฮีป เพราะการที่เราได้รับ:

if (a == b) ===> false

                String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

ในขณะที่.equals()เปรียบเทียบค่าของ String เสมอจึงให้ค่าเป็นจริงในทั้งสองกรณี:

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

ดังนั้นการใช้.equals()ดีกว่าเสมอ


3
.equals () เปรียบเทียบสองอินสแตนซ์อย่างไรก็ตามมีการใช้งานเท่ากับเพื่อเปรียบเทียบ นั่นอาจจะใช่หรือไม่ใช่การเปรียบเทียบผลลัพธ์ของ toString
จาค็อบ

3
@Jacob .equals()วิธีการเรียนวัตถุเปรียบเทียบอินสแตนซ์ (อ้างอิง / ที่อยู่) ซึ่งเป็น.equals()วิธีการเรียน String ถูกแทนที่เพื่อเปรียบเทียบเนื้อหา (ตัวอักษร)
Satyadev

1
ชี้ไปที่ String Pool ได้ดีเมื่อเทียบกับความแตกต่างของฮีป Java เนื่องจากไม่เหมือนกันอย่างแน่นอน ในกลุ่มสตริง Java พยายามStringวัตถุ"แคช" เพื่อบันทึก footprint หน่วยความจำเป็นที่Stringรู้จักกันว่าไม่เปลี่ยนรูป (ฉันหวังว่าฉันพูดอย่างถูกต้องที่นี่) ตรวจสอบstackoverflow.com/questions/3052442/…ด้วย
Roland

1
นี่คือคำตอบที่ฉันต้องการ
Weezy

ช่างเป็นคำตอบที่ยอดเยี่ยม!
alwbtc

223

==การตรวจสอบผู้ประกอบการที่จะดูว่าสองสายตรงวัตถุเดียวกัน

.equals()วิธีการจะตรวจสอบว่าทั้งสองสายมีค่าเดียวกัน


5
โดยทั่วไปฉันขอแนะนำให้ใช้ไลบรารี apache Commons: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/… , java.lang.String)
Marcin Erbel

179

สตริงใน Java ไม่เปลี่ยนรูป ซึ่งหมายความว่าเมื่อใดก็ตามที่คุณพยายามเปลี่ยน / แก้ไขสตริงที่คุณได้รับอินสแตนซ์ใหม่ คุณไม่สามารถเปลี่ยนสตริงเดิมได้ สิ่งนี้ถูกทำขึ้นเพื่อให้สามารถอินสแตนซ์สตริงเหล่านี้ได้ โปรแกรมทั่วไปมีการอ้างอิงสตริงจำนวนมากและการแคชอินสแตนซ์เหล่านี้สามารถลดขนาดหน่วยความจำและเพิ่มประสิทธิภาพของโปรแกรม

เมื่อใช้ตัวดำเนินการ == สำหรับการเปรียบเทียบสตริงคุณไม่ได้เปรียบเทียบเนื้อหาของสตริง แต่จริงๆแล้วเป็นการเปรียบเทียบที่อยู่หน่วยความจำ หากทั้งคู่เท่ากันมันจะคืนค่าจริงและเท็จ โดยที่เท่ากับในสตริงเปรียบเทียบเนื้อหาสตริง

ดังนั้นคำถามคือถ้าสตริงทั้งหมดจะถูกแคชในระบบวิธีการ==กลับมาเป็นเท็จในขณะที่เท่ากับผลตอบแทนจริง อย่างนี้เป็นไปได้ หากคุณสร้างสตริงใหม่เช่นString str = new String("Testing")คุณท้ายสร้างสตริงใหม่ในแคชแม้ว่าแคชมีสตริงที่มีเนื้อหาเดียวกันอยู่แล้ว ในระยะสั้น"MyString" == new String("MyString")มักจะกลับเท็จ

Java ยังพูดถึงฟังก์ชั่นฝึกงาน () ที่สามารถใช้กับสตริงเพื่อทำให้มันเป็นส่วนหนึ่งของแคชดังนั้น"MyString" == new String("MyString").intern()จะกลับจริง

หมายเหตุ: ผู้ให้บริการ == เร็วกว่าเท่ากับเพราะคุณกำลังเปรียบเทียบที่อยู่หน่วยความจำสองแห่ง แต่คุณต้องแน่ใจว่ารหัสไม่ได้สร้างอินสแตนซ์ของสตริงใหม่ในรหัส มิฉะนั้นคุณจะพบข้อบกพร่อง


147
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true

ตรวจสอบให้แน่ใจว่าคุณเข้าใจว่าทำไม เป็นเพราะการ==เปรียบเทียบนั้นเปรียบเทียบการอ้างอิงเท่านั้น equals()วิธีไม่เปรียบเทียบตัวละครโดยตัวละครของเนื้อหา

เมื่อคุณโทรหาใหม่aและbแต่ละคนได้รับการอ้างอิงใหม่ที่ชี้ไปที่"foo"ในตารางสตริง การอ้างอิงแตกต่างกัน แต่เนื้อหาเหมือนกัน


128

ใช่มันไม่ดี ...

==หมายความว่าการอ้างอิงสตริงสองรายการของคุณเป็นวัตถุเดียวกันทั้งหมด คุณอาจเคยได้ยินว่าเป็นกรณีนี้เพราะ Java เก็บตารางตัวอักษร (ซึ่งมัน) แต่เป็นกรณีที่ไม่เสมอ บางสายถูกโหลดด้วยวิธีที่ต่างกันสร้างขึ้นจากสายอื่น ๆ ดังนั้นคุณต้องไม่สมมติว่ามีสองสายเหมือนกันที่จัดเก็บไว้ในตำแหน่งเดียวกัน

เท่ากับการเปรียบเทียบที่แท้จริงสำหรับคุณ


124

ใช่==ไม่ดีสำหรับการเปรียบเทียบสตริง (วัตถุใด ๆ จริง ๆ ยกเว้นคุณจะรู้ว่าพวกมันเป็นที่ยอมรับ) ==เพียงเปรียบเทียบการอ้างอิงวัตถุ .equals()การทดสอบเพื่อความเท่าเทียมกัน สำหรับ Strings บ่อยครั้งที่พวกเขาจะเหมือนกัน แต่เมื่อคุณค้นพบว่าไม่ได้รับประกันเสมอ


118

Java มีพูล String ที่ Java จัดการการจัดสรรหน่วยความจำสำหรับวัตถุ String ดูString Pools ใน Java

เมื่อคุณตรวจสอบ (เปรียบเทียบ) วัตถุสองรายการโดยใช้==โอเปอเรเตอร์จะทำการเปรียบเทียบความเท่าเทียมกันของที่อยู่ลงในสตริพูล หากทั้งสองวัตถุ String มีการอ้างอิงอยู่เดียวกันแล้วก็จะส่งกลับมิฉะนั้นtrue falseแต่ถ้าคุณต้องการเปรียบเทียบเนื้อหาของวัตถุ String สองตัวคุณจะต้องแทนที่equalsเมธอด

equals อันที่จริงแล้วเป็นวิธีการของคลาสวัตถุ แต่มันถูกแทนที่ลงในคลาสสตริงและคำจำกัดความใหม่จะได้รับซึ่งเปรียบเทียบเนื้อหาของวัตถุ

Example:
    stringObjectOne.equals(stringObjectTwo);

แต่ใจมันเคารพกรณีของ String ถ้าคุณต้องการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่คุณจะต้องใช้เมธอด equalsIgnoreCase ของคลาส String

มาดูกัน:

String one   = "HELLO"; 
String two   = "HELLO"; 
String three = new String("HELLO"); 
String four  = "hello"; 

one == two;   // TRUE
one == three; // FALSE
one == four;  // FALSE

one.equals(two);            // TRUE
one.equals(three);          // TRUE
one.equals(four);           // FALSE
one.equalsIgnoreCase(four); // TRUE

7
ฉันเห็นว่านี่เป็นคำตอบสำหรับคำถามใหญ่ ฉันขอสิ่งที่ให้ซึ่งไม่ได้กล่าวถึงในคำตอบที่มีอยู่
ลึกลับ

6
@ อย่างเป็นทางการเขาได้เพิ่มequalsIgnoreCaseซึ่งอาจเป็นข้อมูลสำหรับสดชื่น
AmitG

103

ฉันเห็นด้วยกับคำตอบจาก zacherates

แต่สิ่งที่คุณทำได้คือโทรหาสายintern()อักขระที่ไม่ใช่ตัวอักษร

จากตัวอย่าง zacherates:

// ... but they are not the same object
new String("test") == "test" ==> false 

หากคุณฝึกงานในความเท่าเทียมกันของสตริงที่ไม่ใช่ตัวอักษรคือtrue:

new String("test").intern() == "test" ==> true 

8
นี่ไม่ใช่ความคิดที่ดี การฝึกงานนั้นค่อนข้างแพงและสามารถ (ขัดแย้ง) >> เพิ่ม << หน่วยความจำ JVM ของคุณและเพิ่มต้นทุน GC ในกรณีส่วนใหญ่สิ่งเหล่านี้มีประโยชน์มากกว่าประสิทธิภาพที่ได้จากการใช้==สำหรับการเปรียบเทียบสตริง
สตีเฟ่นซี

101

==เปรียบเทียบการอ้างอิงวัตถุใน Javaและนั่นก็ไม่ใช่ข้อยกเว้นสำหรับStringวัตถุ

สำหรับการเปรียบเทียบเนื้อหาที่แท้จริงของวัตถุ (รวมString) หนึ่งต้องใช้equalsวิธีการ

ถ้าเปรียบเทียบของทั้งสองStringวัตถุที่ใช้==จะออกมาเป็นtrueว่าเป็นเพราะStringวัตถุที่ถูกฝึกงานและโปรแกรม Java Virtual Machine Stringจะมีการอ้างอิงหลายชี้ไปที่อินสแตนซ์เดียวกันของ หนึ่งไม่ควรคาดหวังว่าการเปรียบเทียบหนึ่งStringวัตถุที่มีเนื้อหาเช่นเดียวกับอีกStringวัตถุที่ใช้ในการประเมินเป็น==true


99

.equals()เปรียบเทียบข้อมูลในคลาส (สมมติว่ามีการใช้งานฟังก์ชัน) ==เปรียบเทียบตำแหน่งตัวชี้ (ตำแหน่งของวัตถุในหน่วยความจำ)

==ผลตอบแทนจริงถ้าวัตถุทั้งสอง (ไม่พูดคุยเกี่ยวกับเรื่องส่วนตัว) ชี้ไปที่อินสแตนซ์ของวัตถุเดียวกัน .equals()ผลตอบแทนจริงถ้าวัตถุทั้งสองมีข้อมูลเดียวกันequals()เมื่อเทียบกับ==ใน Java

ที่อาจช่วยคุณ


95

==ทำการตรวจสอบความเท่าเทียมกันของการอ้างอิงไม่ว่าจะเป็น 2 วัตถุ (สตริงในกรณีนี้) หมายถึงวัตถุเดียวกันในหน่วยความจำ

equals()วิธีการจะตรวจสอบว่าเนื้อหาหรือรัฐ 2 วัตถุเหมือนกัน

เห็นได้ชัดว่า==เร็วขึ้น แต่จะ (อาจ) ให้ผลลัพธ์ที่ผิดพลาดในหลายกรณีหากคุณเพียงต้องการบอกว่า 2 Stringวินาทีมีข้อความเหมือนกันหรือไม่

equals()แนะนำให้ใช้วิธีนี้อย่างแน่นอน

ไม่ต้องกังวลกับประสิทธิภาพ บางสิ่งที่กระตุ้นให้ใช้String.equals():

  1. การใช้งานการString.equals()ตรวจสอบครั้งแรกสำหรับความเท่าเทียมกันของการอ้างอิง (โดยใช้==) และถ้า 2 สายเหมือนกันโดยการอ้างอิงจะไม่มีการคำนวณอีกต่อไป!
  2. หากการอ้างอิงสตริง 2 รายการไม่เหมือนกันString.equals()จะตรวจสอบความยาวของสตริงต่อไป เป็นการดำเนินการที่รวดเร็วเนื่องจากStringคลาสเก็บความยาวของสตริงโดยไม่จำเป็นต้องนับอักขระหรือจุดรหัส หากความยาวแตกต่างกันจะไม่มีการตรวจสอบเพิ่มเติมเรารู้ว่าไม่เท่ากับ
  3. เฉพาะในกรณีที่เราได้มาถึงตอนนี้เนื้อหาของทั้งสองสายจะถูกเปรียบเทียบจริงและนี่จะเป็นการเปรียบเทียบสั้น ๆ : ไม่ใช่ตัวละครทุกตัวที่จะถูกเปรียบเทียบถ้าเราพบตัวละครที่ไม่ตรงกัน (ที่ตำแหน่งเดียวกันใน 2 สาย) ) จะไม่มีการตรวจสอบอักขระเพิ่มเติม

เมื่อทุกคนพูดและทำแม้ว่าเราจะรับประกันได้ว่าสายอักขระนั้นเป็นผู้ฝึกงานการใช้equals()วิธีการนั้นยังไม่ได้มีค่าใช้จ่ายที่ใคร ๆ คิดว่าเป็นวิธีที่แนะนำอย่างแน่นอน หากคุณต้องการการตรวจสอบการอ้างอิงที่มีประสิทธิภาพให้ใช้ enums ที่มีการรับรองโดยข้อกำหนดภาษาและการใช้งานที่ค่า enum เดียวกันจะเป็นวัตถุเดียวกัน (โดยการอ้างอิง)


2
Obviously == is faster- อันที่จริงแล้วการ.equals(String)ตรวจเช็คครั้งแรก==ก่อนที่จะมีอย่างอื่นฉันจะบอกว่าความเร็วนั้นเหมือนกัน
Razzle Shazl

2
public boolean equals(Object anObject) { if (this == anObject) { return true; } ...
Razzle Shazl

82

หากคุณเป็นเหมือนฉันเมื่อฉันเริ่มใช้ Java ครั้งแรกฉันต้องการใช้ตัวดำเนินการ "==" เพื่อทดสอบว่าสองอินสแตนซ์สตริงมีค่าเท่ากัน แต่ดีขึ้นหรือแย่ลงนั่นไม่ใช่วิธีที่ถูกต้องใน Java

ในบทช่วยสอนนี้ฉันจะสาธิตวิธีที่แตกต่างกันหลายวิธีเพื่อเปรียบเทียบสตริง Java อย่างถูกต้องโดยเริ่มจากวิธีที่ฉันใช้เป็นส่วนใหญ่ ในตอนท้ายของบทช่วยสอนการเปรียบเทียบ Java String นี้ฉันจะกล่าวถึงสาเหตุที่ตัวดำเนินการ "==" ไม่ทำงานเมื่อเปรียบเทียบสตริง Java

ตัวเลือกที่ 1: การเปรียบเทียบ Java String กับวิธีการเท่ากับ ส่วนใหญ่เวลา (อาจ 95% ของเวลา) ฉันเปรียบเทียบสตริงกับวิธีการเท่ากับของคลาส Java String เช่นนี้:

if (string1.equals(string2))

String นี้เท่ากับวิธีที่ดูที่สองสตริง Java และถ้าพวกเขามีสตริงที่เหมือนกันแน่นอนตัวอักษรพวกเขาจะถือว่าเท่าเทียมกัน

ลองดูตัวอย่างการเปรียบเทียบสตริงด่วนด้วยเมธอด equals หากรันการทดสอบต่อไปนี้ทั้งสองสตริงจะไม่ถูกพิจารณาว่าเท่ากันเนื่องจากอักขระไม่เหมือนกันทุกประการ (กรณีของอักขระแตกต่างกัน):

String string1 = "foo";
String string2 = "FOO";

if (string1.equals(string2))
{
    // this line will not print because the
    // java string equals method returns false:
    System.out.println("The two strings are the same.")
}

แต่เมื่อทั้งสองสายมีสายอักขระที่เหมือนกันแน่นอนวิธีการเท่ากับจะกลับจริงเช่นในตัวอย่างนี้:

String string1 = "foo";
String string2 = "foo";

// test for equality with the java string equals method
if (string1.equals(string2))
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

ตัวเลือกที่ 2: การเปรียบเทียบสตริงกับเมธอด equalsIgnoreCase

ในการทดสอบเปรียบเทียบสตริงคุณจะต้องเพิกเฉยไม่ว่าสตริงนั้นจะเป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก เมื่อคุณต้องการทดสอบสตริงของคุณสำหรับความเท่าเทียมกันในลักษณะที่ไม่คำนึงถึงขนาดตัวพิมพ์ให้ใช้เมธอด equalsIgnoreCase ของคลาส String เช่นนี้

String string1 = "foo";
String string2 = "FOO";

 // java string compare while ignoring case
 if (string1.equalsIgnoreCase(string2))
 {
     // this line WILL print
     System.out.println("Ignoring case, the two strings are the same.")
 }

ตัวเลือก 3: การเปรียบเทียบสตริงของ Java กับเมธอด comparTo

นอกจากนี้ยังมีวิธีที่สามที่พบได้น้อยกว่าในการเปรียบเทียบสตริง Java และนั่นคือด้วยเมธอด String classToTo ถ้าทั้งสองสายเหมือนกันทุกประการวิธีเปรียบเทียบกับจะส่งคืนค่า 0 (ศูนย์) นี่คือตัวอย่างคร่าวๆของวิธีการเปรียบเทียบสตริงนี้:

String string1 = "foo bar";
String string2 = "foo bar";

// java string compare example
if (string1.compareTo(string2) == 0)
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

ในขณะที่ฉันกำลังเขียนเกี่ยวกับแนวคิดเรื่องความเท่าเทียมกันใน Java สิ่งสำคัญคือต้องทราบว่าภาษา Java มีวิธีการเท่ากับในคลาส Java Object Object เมื่อใดก็ตามที่คุณกำลังสร้างวัตถุของคุณเองและคุณต้องการที่จะให้วิธีการดูว่าวัตถุสองอย่างของคุณ "เท่ากัน" คุณควรจะแทนที่ (และนำไปใช้) วิธีนี้เท่ากับในชั้นเรียนของคุณ (ในลักษณะเดียวกับภาษา Java พฤติกรรมความเท่าเทียมกัน / การเปรียบเทียบนี้ในเมธอด String เท่ากับ)

คุณอาจต้องการดู==, .equals (), comparTo () และ compar ()


5
สำหรับตัวอักษรสตริง Like String string1 = "foo bar"; String string2 = "foo bar"; คุณสามารถใช้ตัวดำเนินการ == เพื่อทดสอบความเท่าเทียมกันของเนื้อหาได้โดยตรง
JAVA

1
ใน google apps สคริปต์ "comparTo" ไม่น่าจะเป็นไปได้ ฉันลอง instaed "เท่ากับ" นี่เป็นทางออกเดียวที่ทำงาน ....
user3887038

77

ฟังก์ชั่น:

public float simpleSimilarity(String u, String v) {
    String[] a = u.split(" ");
    String[] b = v.split(" ");

    long correct = 0;
    int minLen = Math.min(a.length, b.length);

    for (int i = 0; i < minLen; i++) {
        String aa = a[i];
        String bb = b[i];
        int minWordLength = Math.min(aa.length(), bb.length());

        for (int j = 0; j < minWordLength; j++) {
            if (aa.charAt(j) == bb.charAt(j)) {
                correct++;
            }
        }
    }

    return (float) (((double) correct) / Math.max(u.length(), v.length()));
}

ทดสอบ:

String a = "This is the first string.";

String b = "this is not 1st string!";

// for exact string comparison, use .equals

boolean exact = a.equals(b);

// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote

float similarity = simple_similarity(a,b);

6
สิ่งนี้แตกต่างจากคำตอบอื่น ๆ อย่างไร และทำไมจึงเป็นไปตามที่คุณแนะนำ
user151019

2
@ Mark คำถามเกี่ยวกับความแตกต่างระหว่าง==และequalsได้รับคำตอบแล้วโดยวิธีแก้ไขปัญหาอื่น ๆ ฉันเพิ่งเสนอวิธีที่แตกต่างในการเปรียบเทียบสตริงในลักษณะที่หลวม
Khaled.K

77

==ตรวจสอบผู้ประกอบการถ้าสองอ้างอิงชี้ไปที่วัตถุเดียวกันหรือไม่ .equals()ตรวจสอบเนื้อหาสตริงจริง (ค่า)

โปรดทราบว่า.equals()วิธีการเป็นของชั้นเรียนObject(ชั้นซุปเปอร์ของทุกชั้นเรียน) คุณต้องลบล้างมันตามความต้องการของคลาส แต่สำหรับ String นั้นมีการใช้งานแล้วและตรวจสอบว่ามีสองสตริงที่มีค่าเหมือนกันหรือไม่

  • กรณีที่ 1

    String s1 = "Stack Overflow";
    String s2 = "Stack Overflow";
    s1 == s2;      //true
    s1.equals(s2); //true

    สาเหตุ: สตริงตัวอักษรที่สร้างขึ้นโดยไม่มีค่า null จะถูกเก็บไว้ใน String Pool ในพื้นที่ permgen ของฮีป ดังนั้นทั้ง s1 และ s2 ชี้ไปที่วัตถุเดียวกันในกลุ่ม

  • กรณีที่ 2

    String s1 = new String("Stack Overflow");
    String s2 = new String("Stack Overflow");
    s1 == s2;      //false
    s1.equals(s2); //true

    สาเหตุ: ถ้าคุณสร้างวัตถุสตริงโดยใช้newคำสำคัญจะมีการจัดสรรพื้นที่แยกต่างหากไว้บนฮีป


53

==เปรียบเทียบค่าอ้างอิงของวัตถุในขณะที่equals()วิธีการที่มีอยู่ในjava.lang.Stringชั้นเรียนเปรียบเทียบเนื้อหาของStringวัตถุ (กับวัตถุอื่น)


15
เพื่อไม่ให้จู้จี้จุกจิก แต่equals()วิธีการที่Stringเป็นจริงในStringชั้นเรียนไม่ได้Objectมา ค่าเริ่มต้นequals()ในObjectจะไม่เปรียบเทียบว่าเนื้อหาเหมือนกันและในความเป็นจริงก็แค่คืนค่าจริงเมื่อการอ้างอิงเหมือนกัน
Jacob Schoen

1
@JacobSchoen: ลิงก์ด้านบนไม่ทำงานอีกต่อไปเนื่องจาก GrepCode หยุดทำงาน นี่คือทางเลือกสำหรับการใช้งานที่เท่าเทียมกัน: [Inline Link] ( zgrepcode.com/java/openjdk/10.0.2/java.base/java/lang/… )
Amandeep Singh

50

ฉันคิดว่าเมื่อคุณกำหนดStringคุณกำหนดวัตถุ .equals()ดังนั้นคุณจำเป็นต้องใช้ เมื่อคุณใช้ชนิดข้อมูลดั้งเดิมที่คุณใช้==แต่ด้วยString(และวัตถุใด ๆ ) .equals()คุณต้องใช้


7
"char []" ไม่ใช่ประเภทข้อมูลดั้งเดิม! มันเป็นชุดของ "ถ่าน" และอาร์เรย์ไม่ใช่ข้อมูลดั้งเดิมที่พิมพ์ด้วยตนเอง
Christian

48

หากequals()วิธีนี้มีอยู่ในjava.lang.Objectชั้นเรียนและคาดว่าจะตรวจสอบความเท่าเทียมกันของสถานะของวัตถุ! นั่นหมายถึงเนื้อหาของวัตถุ ในขณะที่==ผู้ประกอบการคาดว่าจะตรวจสอบอินสแตนซ์ของวัตถุจริงเหมือนกันหรือไม่

ตัวอย่าง

พิจารณาตัวแปรอ้างอิงที่แตกต่างกันสองแบบstr1และstr2:

str1 = new String("abc");
str2 = new String("abc");

ถ้าคุณใช้ equals()

System.out.println((str1.equals(str2))?"TRUE":"FALSE");

คุณจะได้รับออกเป็นถ้าคุณใช้ TRUE==

System.out.println((str1==str2) ? "TRUE" : "FALSE");

ตอนนี้คุณจะได้รับFALSEผลลัพธ์เป็นเพราะทั้งสองstr1และstr2ชี้ไปที่วัตถุที่แตกต่างกันถึงแม้ว่าทั้งสองจะใช้เนื้อหาสตริงเดียวกัน มันเป็นเพราะnew String()วัตถุใหม่ถูกสร้างขึ้นทุกครั้ง


43

ตัวดำเนินการ==มีความหมายเสมอสำหรับการเปรียบเทียบการอ้างอิงวัตถุในขณะที่เมธอด String class .equals ()ถูกแทนที่สำหรับการเปรียบเทียบเนื้อหา :

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)

40

วัตถุทั้งหมดรับประกันว่าจะมี.equals()วิธีการตั้งแต่ Object มีวิธีการ.equals()ที่ส่งกลับแบบบูล มันเป็นงานของคลาสย่อยเพื่อแทนที่เมธอดนี้หากจำเป็นต้องนิยามเพิ่มเติม ไม่มีมัน (เช่นใช้==) ที่อยู่หน่วยความจำเท่านั้นที่จะถูกตรวจสอบระหว่างสองวัตถุเพื่อความเท่าเทียมกัน String แทนที่.equals()เมธอดนี้และแทนที่จะใช้แอดเดรสหน่วยความจำจะส่งคืนการเปรียบเทียบสตริงที่ระดับอักขระเพื่อความเท่าเทียมกัน

หมายเหตุสำคัญคือสตริงจะถูกเก็บไว้ในก้อนเดียวดังนั้นเมื่อมีการสร้างสตริงมันจะถูกเก็บไว้ตลอดไปในโปรแกรมที่อยู่เดียวกัน สตริงไม่เปลี่ยนแปลงพวกเขาจะไม่เปลี่ยนรูป นี่คือเหตุผลว่าทำไมจึงควรใช้การเรียงสตริงปกติหากคุณมีจำนวนของการประมวลผลสตริงที่ร้ายแรง แต่คุณจะใช้StringBuilderคลาสที่มีให้ โปรดจำไว้ว่าพอยน์เตอร์ของสตริงนี้สามารถเปลี่ยนแปลงได้และหากคุณสนใจที่จะดูว่าตัวชี้สองตัวเหมือนกัน==จะเป็นวิธีที่ดีหรือไม่ เงื่อนไขตัวเองไม่ได้


2
"เมื่อสตริงถูกสร้างขึ้นมันจะถูกเก็บไว้ตลอดไปในโปรแกรมที่ที่อยู่เดียวกัน" - นี่เป็นการผิดพลาด เฉพาะการแสดงออกของสตริงคงที่เวลาคอมไพล์ (อาจเกี่ยวข้องกับfinal Stringตัวแปร) และสตริงที่โปรแกรมของคุณฝึกงานอย่างชัดเจนจะถูกเก็บไว้ในสิ่งที่คุณเรียกว่า "ก้อนสระ" Stringวัตถุอื่น ๆ ทั้งหมดอยู่ภายใต้การรวบรวมขยะเมื่อไม่มีการอ้างอิงสดอีกต่อไปเช่นเดียวกับวัตถุประเภทอื่น นอกจากนี้ในขณะที่ความไม่สามารถเปลี่ยนแปลงได้นั้นเป็นสิ่งจำเป็นสำหรับกลไกการฝึกงานทั้งหมดในการทำงาน แต่ก็ไม่เกี่ยวข้องกับสิ่งนี้
Ted Hopp

การเปรียบเทียบสตริงจะกระทำผ่านวิธีเท่ากับหรือ equalsIgnoreCase ซึ่งจริง ๆ แล้วเปรียบเทียบเนื้อหาของสตริง แต่ == ลงชื่อเพียงตรวจสอบค่าอ้างอิง สำหรับตัวอักษรสตริงจากกลุ่มสตริงจะทำงานได้ดีสำหรับกรณีนี้ String s1 = new String ("a"); String s2 = new String ("a"); ในกรณีนี้ s1 == s2 เป็นเท็จ แต่ s1.equals (s2) เป็นจริง
Shailendra Singh

39

คุณยังสามารถใช้compareTo()วิธีการเปรียบเทียบสองสาย หากผลลัพธ์ CompareTo เป็น 0 ดังนั้นทั้งสองสตริงจะเท่ากันมิฉะนั้นสตริงที่เปรียบเทียบจะไม่เท่ากัน

==เปรียบเทียบอ้างอิงและไม่ได้เปรียบเทียบสตริงที่เกิดขึ้นจริง หากคุณสร้างทุก ๆ สตริงโดยใช้new String(somestring).intern()คุณสามารถใช้==โอเปอเรเตอร์เพื่อเปรียบเทียบสองสตริงมิฉะนั้นเท่ากับ () หรือเมธอด comparTo สามารถใช้ได้


35

ใน Java เมื่อมีการใช้ตัวดำเนินการ“ ==”เพื่อเปรียบเทียบ 2 วัตถุมันจะตรวจสอบว่าวัตถุนั้นอ้างถึงสถานที่เดียวกันในหน่วยความจำหรือไม่ มันตรวจสอบเพื่อดูว่าชื่อวัตถุ 2 ชื่อนั้นอ้างอิงไปยังตำแหน่งหน่วยความจำเดียวกันหรือไม่

คลาส Java String จริง ๆ แล้วแทนที่การใช้งานเริ่มต้นเท่ากับ () ในคลาส Object - และมันจะแทนที่วิธีการเพื่อให้ตรวจสอบเฉพาะค่าของสตริงที่ไม่ใช่สถานที่ในหน่วยความจำ ซึ่งหมายความว่าหากคุณเรียกใช้เมธอด equals () เพื่อเปรียบเทียบ 2 วัตถุ String แล้วตราบเท่าที่ลำดับของอักขระที่แท้จริงมีค่าเท่ากันวัตถุทั้งสองจะถือว่าเท่ากัน

==การตรวจสอบผู้ประกอบการถ้าสองสายตรงวัตถุเดียวกัน

.equals()วิธีการตรวจสอบถ้าสองสายมีค่าเดียวกัน


1
เว้นแต่หนึ่งในนั้นเป็นโมฆะเนื่องจาก s.equals (s2) จะผิดพลาดถ้า s เป็นโมฆะทำให้การเปรียบเทียบล้มเหลว แน่นอนว่ามันไม่ได้ขัดแย้งกับคำตอบจริงๆ มันเป็นเพียงข้อแม้
Jon Coombs

1
ไม่จะไม่ผิดพลาดมันจะส่ง NullPointerException ทำให้การเปรียบเทียบไม่เกิดขึ้น
Bludzee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.