מקור: ליצור מחרוזת Java באמצעות " " או קונסטרוקטור? על ידי X Wang ב-Java, ניתן ליצור מחרוזת בשתי שיטות:
String x = "abc";
String y = new String("abc");
מה ההבדל בין שימוש במירכאות כפולות לבין שימוש בבנאי?
1. מרכאות כפולות לעומת בַּנַאִי
על שאלה זו ניתן לענות על ידי התבוננות בשתי דוגמאות פשוטות. דוגמה 1:String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True
a==b
נכון מכיוון a
ששניהם b
מתייחסים לאותו אובייקט - מחרוזת המוצהרת כמילולית (מחרוזת מילולית למטה) באזור השיטה (אנו מפנים את הקורא למקור במשאב שלנו: Top 8 דיאגרמות להבנת Java , דיאגרמה 8). כאשר אותה מחרוזת מילולית נוצרת יותר מפעם אחת, רק עותק אחד של המחרוזת מאוחסן בזיכרון, רק מופע אחד שלו (במקרה שלנו "abcd"). זה נקרא "התמחות במיתרים". כל קבועי המחרוזות המעובדים בזמן הקומפילציה מאומנים אוטומטית ב-Java. דוגמה 2:
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
c==d
שקר מכיוון c
שהם d
מתייחסים לשני אובייקטים שונים בזיכרון (על הערימה). לאובייקטים שונים יש תמיד הפניות שונות. תרשים זה ממחיש את שני המצבים שתוארו לעיל:
2. מיתרים מתמחים בשלב ביצוע התוכנית
המחבר מודה ללוקאס אדר (ההערה למטה היא שלו): התמחות מחרוזת יכולה להתרחש גם במהלך הפעלת תוכנית, גם אם נוצרות שתי מחרוזות באמצעות בנאים:String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d); // Now true
System.out.println(c.equals(d)); // True
3. מתי להשתמש במירכאות כפולות ומתי להשתמש בבנאים
בשל העובדה כי "abcd" המילולי הוא תמיד מסוג String, שימוש בקונסטרוקטור יצור אובייקט מיותר נוסף. אז יש להשתמש במירכאות כפולות אם אתה רק צריך ליצור מחרוזת. אם אתה באמת צריך ליצור אובייקט חדש בערימה, עליך להשתמש בקונסטרוקטור. מקרי שימוש מוצגים כאן (מקורי) . (אני מספק את הטקסט המתורגם למטה. אבל אני עדיין ממליץ לך בחום להכיר את קוד הפרשנים בקישור הזה.)שיטת substring() ב-JDK 6 ו-JDK 7
שיטת substring() ב-JDK 6 ו-JDK 7 מאת X Wang השיטהsubstring(int beginIndex, int endIndex)
ב-JDK 6 ו-JDK 7 שונה. הכרת ההבדלים הללו יכולה לעזור לך להשתמש בשיטה זו בצורה טובה יותר. למען נוחות הקריאה, להלן substring()
נתכוון לתחביר המלא, כלומר. substring(int beginIndex, int endIndex)
.
1. מה עושה substring()?
השיטהsubstring(int beginIndex, int endIndex)
מחזירה מחרוזת שמתחילה במספר תו beginIndex
ומסתיימת במספר תו endIndex-1
.
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
תְפוּקָה:
bc
2. מה קורה כאשר תת-מחרוזת () נקראת?
אתה אולי יודע שבגלל אי-השינויx
, כאשר מקצה x את התוצאה של x.substring(1,3)
, x
הוא מצביע על שורה חדשה לגמרי (ראה תרשים): עם זאת, דיאגרמה זו אינה נכונה לחלוטין; זה לא מדגים מה באמת קורה בערימה. מה שקורה בפועל כשנקרא substring()
שונה ב-JDK 6 וב-JDK 7.
3. substring() ב-JDK 6
סוג המחרוזת נתמך על ידי סוג מערךchar
. ב-JDK 6, המחלקה String
מכילה 3 שדות: char value[]
, int offset
, int count
. הם משמשים לאחסון מערך התווים בפועל, האינדקס של התו הראשון במערך, מספר התווים בשורה. כאשר השיטה נקראת substring()
, היא יוצרת שורה חדשה, אך הערך של המשתנה עדיין מצביע על אותו מערך בערימה. ההבדל בין שתי מחרוזות הוא מספר התווים שלהן וערך האינדקס של התו ההתחלתי במערך. הקוד שלהלן הוא פשוט ומכיל רק את היסודות כדי להדגים את הבעיה.
//JDK 6
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
4. בעיה הנגרמת על ידי substring() ב-JDK 6
אם יש לך מחרוזת ארוכה מאוד, אבל אתה צריך רק חלק קטן ממנו, אותו אתה מקבל בכל פעם שאתה משתמשsubstring()
. זה יגרום לבעיות ביצוע, מכיוון שאתה צריך רק חלק קטן, אבל אתה עדיין צריך לאחסן את המחרוזת כולה. עבור JDK 6, הפתרון הוא הקוד שלהלן, שיטיל את המחרוזת למחרוזת משנה אמיתית:
x = x.substring(x, y) + ""
המשתמש STepeR ניסח שאלה (ראה הערה שלו), ונראה היה צורך להוסיף את סעיף 4. "בעיה הנגרמת substring()
ב-JDK 6" היא דוגמה נרחבת יותר. אני מקווה שזו תהיה התשובה ותעזור לאחרים להבין במהירות מה הבעיה. הנה הקוד:
String a = "aLongLongString";
String b = a.substring(1, 2);
String c = a.substring(2, 6);
לכן, ב-JDK 7 b
, אובייקטים с
מסוג a String
שנוצרו על ידי קריאה למתודה substring()
על אובייקט מסוג a String
יפנו לשני מערכים שזה עתה נוצרו בערימה- L
for b
, ongL
for c
. שני המערכים החדשים הללו יאוחסנו בערימה יחד עם המערך המקורי aLongLongString
שאליו מתייחס א. הָהֵן. המערך המקורי לא נעלם לשום מקום. כעת נחזור ל-JDK 6. ב-JDK 6, ערימה מכילה מערך בודד aLongLongString
. לאחר ביצוע שורות הקוד
String b = a.substring(1, 2);
String c = a.substring(2, 6);
אובייקטים b
מתייחסים c
לאותו מערך בערימה, המתאים לאובייקט a
: b
- לאלמנטים מהאינדקס הראשון עד ה-2, c
- לאלמנטים מהאינדקס השני עד ה-6 (המספור מתחיל מ-0, תזכורת). הָהֵן. ברור שכל גישה נוספת למשתנים b
או c ב-JDK 6 תגרום למעשה לכך שהאלמנטים הרצויים של המערך המקורי "ייספרו" בערימה. ב-JDK 7, כל גישה נוספת למשתנים b
או c תגרום לגישה למערכים הקטנים יותר הדרושים, שכבר נוצרו ו"חיים" בערימה. הָהֵן. ברור ש-JDK 7 משתמש יותר פיזית בזיכרון במצבים כאלה. אבל בואו נדמיין אפשרות אפשרית: מחרוזות משנה מסוימות של המשתנה מוקצות למשתנים b
, ובעתיד כולם משתמשים רק בהם - אובייקטים ו . אף אחד פשוט לא ניגש יותר למשתנה a; אין לו התייחסות (לכך מתכוון מחבר המאמר). כתוצאה מכך, בשלב מסוים בזמן, אוסף האשפה מופעל, ו(בצורה הכללית ביותר, כמובן) אנו מקבלים 2 מצבים שונים: JDK 6 : החפץ נהרס (אשפה נאסף) , אבל - הענק המקורי המערך בערימה חי; הוא נמצא בשימוש כל הזמן ו . JDK 7: אובייקט a מושמד יחד עם המערך המקורי בערימה. זו הנקודה ב-JDK 6 שיכולה להוביל לדליפת זיכרון. c
a
b
c
a
b
c
5. substring() ב-JDK 7
השיטה שופרה ב-JDK 7. ב-JDK 7substring()
הוא למעשה יוצר מערך חדש בערימה.
//JDK 7
public String(char value[], int offset, int count) {
//check boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
GO TO FULL VERSION