การเปรียบเทียบสตริงใน Java

ใน Java Stringคลาสจะห่อหุ้มอาร์เรย์ของchar. พูดง่ายๆStringคืออาร์เรย์ของอักขระที่ใช้ในการแต่งคำประโยคหรือข้อมูลอื่น ๆ ที่คุณต้องการ

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

เมื่อคุณดูStringคลาสใน Java คุณจะเห็นว่าอาร์เรย์ของการcharห่อหุ้ม:

 public String(char value[]) { this(value, 0, value.length, null); } 

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

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

 public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {} // And so on…... 

มากกว่าที่จะพยายามที่จะเข้าใจว่าStringระดับการทำงานนี้ Java ชาเลนเจอร์จะช่วยให้คุณเข้าใจสิ่งที่มันไม่และวิธีการที่จะใช้มันในรหัสของคุณ

String Pool คืออะไร?

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

ราฟาเอลชิเนลาโตเดลเนโร

แม้ว่าเราจะสร้างStringตัวแปรสำหรับDukeและJuggyStrings แต่มีเพียงสองวัตถุเท่านั้นที่ถูกสร้างและเก็บไว้ในฮีปหน่วยความจำ สำหรับการพิสูจน์โปรดดูตัวอย่างโค้ดต่อไปนี้ (โปรดจำไว้ว่าตัว==ดำเนินการ“” ใน Java ใช้เพื่อเปรียบเทียบออบเจ็กต์สองชิ้นและพิจารณาว่าเหมือนกันหรือไม่)

 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy); 

รหัสนี้จะส่งคืนtrueเนื่องจากทั้งสองStringชี้ไปที่วัตถุเดียวกันในStringพูล ค่าของพวกเขาเหมือนกัน

ข้อยกเว้น: ตัวดำเนินการ "ใหม่"

ตอนนี้ดูรหัสนี้ - ดูเหมือนกับตัวอย่างก่อนหน้านี้ แต่มีความแตกต่าง

 String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke); 

อ้างอิงจากตัวอย่างก่อนหน้านี้คุณอาจคิดว่ารหัสนี้จะกลับมาแต่ก็จริงtrue falseการเพิ่มตัวnewดำเนินการบังคับให้สร้างใหม่Stringในฮีปหน่วยความจำ ดังนั้น JVM จะสร้างวัตถุสองชิ้นที่แตกต่างกัน

วิธีการดั้งเดิม

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

สตริงพูลและวิธีการฝึกงาน ()

ในการจัดเก็บStringในStringสระว่ายน้ำที่เราใช้เทคนิคที่เรียกว่าฝึกงานString นี่คือสิ่งที่ Javadoc บอกเราเกี่ยวกับintern()วิธีการ:

 /** * Returns a canonical representation for the string object. * * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * * 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. * * 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}. * * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * The Java™ Language Specification. * * @returns 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(); 

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

ตอนนี้สังเกตว่าจะเกิดอะไรขึ้นเมื่อเราใช้newคำหลักเพื่อบังคับให้สร้างสองStrings:

 String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); // The result will be false here System.out.println(duke.intern() == duke2.intern()); // The result will be true here 

ไม่เหมือนกับตัวอย่างก่อนหน้านี้ที่มีnewคำหลักในกรณีนี้การเปรียบเทียบจะกลายเป็นจริง นั่นเป็นเพราะการใช้intern()วิธีนี้ทำให้มั่นใจได้ว่าStrings จะถูกเก็บไว้ในพูล

เมธอดเท่ากับคลาส String

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

ลองดูสิ:

 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; } 

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

วิธีการสตริงทั่วไปส่วนใหญ่

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

 // Removes spaces from the borders trim() // Gets a substring by indexes substring(int beginIndex, int endIndex) // Returns the characters length of the String length() // Replaces String, regex can be used. replaceAll(String regex, String replacement) // Verifies if there is a specified CharSequence in the String contains(CharSequences) 

ท้าทายการเปรียบเทียบสตริง!

มาลองทำสิ่งที่คุณได้เรียนรู้เกี่ยวกับStringชั้นเรียนด้วยความท้าทายสั้น ๆ

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

 public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } } 

ผลลัพธ์ใดแทนค่าสุดท้ายของตัวแปรผลลัพธ์

ตอบ : 02468

B : 12469

C : 12579

D : 12568

ตรวจสอบคำตอบของคุณที่นี่

เกิดอะไรขึ้น? ทำความเข้าใจพฤติกรรมสตริง

ในบรรทัดแรกของโค้ดเราจะเห็น:

 result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; 

แม้ว่าStringจะเหมือนกันหลังจากtrim()เรียกใช้เมธอดแล้ว แต่String“ powerfulcode “ในตอนแรกก็แตกต่างกัน ในกรณีนี้การเปรียบเทียบคือfalseเนื่องจากเมื่อtrim()วิธีการลบช่องว่างออกจากเส้นขอบจะบังคับให้สร้างใหม่Stringด้วยตัวดำเนินการใหม่

ต่อไปเราจะเห็น:

 result += "flexibleCode" == "flexibleCode" ? "2" : "3"; 

No mystery here, the Strings are the same in the String pool. This comparison returns true.

Next, we have:

 result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; 

Using the new reserved keyword forces the creation of two new Strings, whether they are equal or not. In this case the comparison will be false even if the String values are the same.

Next is:

 result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; 

Because we’ve used the equals() method, the value of the String will be compared and not the object instance. In that case, it doesn’t matter if the objects are different because the value is being compared. This comparison returns true.

Finally, we have:

 result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; 

As you’ve seen before, the intern() method puts the String in the String pool. Both Strings point to the same object, so in this case the comparison is true.

Video challenge! Debugging String comparisons

Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain the Java Strings challenge:

Common mistakes with Strings

It can be difficult to know if two Strings are pointing to the same object, especially when the Strings contain the same value. It helps to remember that using the reserved keyword new always results in a new object being created in memory, even if the values are the same.

Using String methods to compare Object references can also be tricky. The key is, if the method changes something in the String, the object references will be different.

A few examples to help clarify:

 System.out.println("duke".trim() == "duke".trim());; 

This comparison will be true because the trim() method does not generate a new String.

 System.out.println(" duke".trim() == "duke".trim()); 

In this case, the first trim() method will generate a new String because the method will execute its action, so the references will be different.

Finally, when trim() executes its action, it creates a new String:

 // Implementation of the trim method in the String class new String(Arrays.copyOfRange(val, index, index + len), LATIN1); 

What to remember about Strings

  • Strings are immutable, so a String’s state can’t be changed.
  • To conserve memory, the JVM keeps Strings in a String pool. When a new String is created, the JVM checks its value and points it to an existing object. If there is no String with that value in the pool, then the JVM creates a new String.
  • การใช้ตัว==ดำเนินการเปรียบเทียบการอ้างอิงวัตถุ ใช้equals()วิธีการเปรียบเทียบค่าของไฟล์String. กฎเดียวกันนี้จะถูกนำไปใช้กับวัตถุทั้งหมด
  • เมื่อใช้ตัวnewดำเนินการตัวใหม่Stringจะถูกสร้างขึ้นในStringพูลแม้ว่าจะStringมีค่าเดียวกันก็ตาม

 

คีย์คำตอบ

คำตอบนี้ผู้ท้าชิง Java 12568เป็นตัวเลือกที่ดีเอาท์พุทจะเป็น

เรื่องนี้ "การเปรียบเทียบสตริงใน Java" เผยแพร่ครั้งแรกโดย JavaWorld