השוואות מחרוזות בג'אווה

ב- Java Stringהמחלקה מצמידה מערך של char. במילים פשוטות, Stringהוא מערך תווים המשמש לחיבור מילים, משפטים או כל נתונים אחרים שתרצו.

אנקפסולציה היא אחד המושגים החזקים ביותר בתכנות מונחה עצמים. בגלל אנקפסולציה, אינך צריך לדעת כיצד עובד מעמד המחרוזת; אתה רק צריך לדעת באילו שיטות להשתמש בממשק שלו.

כשאתה מסתכל על Stringהכיתה בג'אווה, אתה יכול לראות כיצד מערך של 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 Challenger זה יעזור לך להבין מה הוא עושה וכיצד להשתמש בו בקוד שלך.

מהי בריכת מיתרים?

Stringהיא אולי המחלקה הנפוצה ביותר ב- Java. אם נוצר אובייקט חדש בערמת הזיכרון בכל פעם שהשתמשנו ב- String, נבזבז הרבה זיכרון. Stringברכה פותר בעיה זו על ידי אחסון פשוט אובייקט אחד לכל Stringערך, כפי שמוצג להלן.

רפאל צ'ינלאטו דל נירו

למרות שיצרנו Stringמשתנה עבור ה- Dukeו- JuggyStrings, רק שני אובייקטים נוצרים ומאוחסנים בערמת הזיכרון. להוכחה, עיין בדוגמת הקוד הבאה. (זכור ==שהמפעיל " " בג'אווה משמש להשוואה בין שני אובייקטים ולקבוע אם הם זהים.)

 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לכליאה . הנה מה שג'אדוק אומר לנו על 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במילת המפתח כדי לאלץ יצירת שני Stringשניות:

 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 יאוחסנו בבריכה.

שווה שווה למעמד מחרוזת

equals()השיטה משמשת כדי לאמת אם המדינה משתי כיתות ג 'אווה זהה. מכיוון equals()שהוא Objectמהמחלקה, כל מחלקת Java יורשת אותו. אבל equals()צריך לדרוס את השיטה כדי לגרום לה לעבוד כמו שצריך. כמובן, Stringעוקף equals().

התבונן:

 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

ב : 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 זה הוא אפשרות D. הפלט יהיה 12568.

סיפור זה, "השוואות מיתרים ב- Java" פורסם במקור בהוצאת JavaWorld.