ภาพรวม
StringBuilder และ StringBuffer เป็นแนวคิดที่สับสนสองประการ บทความนี้เริ่มต้นจากซอร์สโค้ดและดูที่ความเหมือนและความแตกต่างระหว่างทั้งสอง
เป็นเรื่องง่ายที่จะรู้ว่าหนึ่งในสองนี้คือเธรดที่ปลอดภัยและหนึ่งในเธรดที่ปลอดภัยนั้นไม่มีประสิทธิภาพ
คำอธิบายใน Java Doc
Java Doc เป็นคำอธิบายประกอบที่เขียนโดยผู้ที่เขียนซอร์สโค้ด มาดู Java Doc ก่อน
สตริง
ลำดับอักขระที่ไม่แน่นอน คลาสนี้ให้ API เข้ากันได้กับ StringBuffer แต่ไม่มีการรับประกันการซิงโครไนซ์ คลาสนี้ได้รับการออกแบบมาเพื่อใช้เป็นตัวแทนที่แบบดรอปอินสำหรับ StringBuffer ในสถานที่ที่มีการใช้บัฟเฟอร์สตริงโดยเธรดเดี่ยว (โดยทั่วไปเป็นกรณี) หากเป็นไปได้ขอแนะนำให้ใช้คลาสนี้ในการตั้งค่ากับ StringBuffer เนื่องจากจะเร็วขึ้นภายใต้การใช้งานส่วนใหญ่
การดำเนินการหลักของ StringBuilder คือวิธีการต่อท้ายและแทรกซึ่งมีการโอเวอร์โหลดเพื่อรับข้อมูลทุกประเภท แต่ละตัวแปลงข้อมูลที่กำหนดเป็นสตริงได้อย่างมีประสิทธิภาพแล้วผนวกหรือแทรกอักขระของสตริงนั้นเป็นตัวสร้างสตริง วิธีการภาคผนวกจะเพิ่มอักขระเหล่านี้ในตอนท้ายของผู้สร้างเสมอ วิธีการแทรกเพิ่มอักขระที่จุดที่ระบุ
ตัวอย่างเช่นถ้า Z หมายถึงวัตถุตัวสร้างสตริงที่มีเนื้อหาปัจจุบันคือ "เริ่มต้น" ดังนั้นวิธีการเรียก z.append ("le") จะทำให้ตัวสร้างสตริงมี "startle" ในขณะที่ z.insert (4, "le") จะเปลี่ยนตัวสร้างสตริงให้มี "starlet"
โดยทั่วไปหากผู้อ้างอิง SB ไปยังอินสแตนซ์ของ StringBuilder ดังนั้น SB.Append (X) จะมีเอฟเฟกต์เช่นเดียวกับ SB.INSERT (SB.Length (), X)
ตัวสร้างสตริงทุกตัวมีความจุ ตราบใดที่ความยาวของลำดับอักขระที่มีอยู่ในตัวสร้างสตริงไม่เกินความจุไม่จำเป็นต้องจัดสรรบัฟเฟอร์ภายในใหม่ หากบัฟเฟอร์ภายในล้นมันจะมีขนาดใหญ่ขึ้นโดยอัตโนมัติ
อินสแตนซ์ของ StringBuilder ไม่ปลอดภัยสำหรับการใช้งานหลายเธรด หากจำเป็นต้องมีการซิงโครไนซ์ดังกล่าวขอแนะนำให้ใช้ java.lang.stringbuffer
เว้นแต่จะระบุไว้เป็นอย่างอื่นการผ่านอาร์กิวเมนต์ null ไปยังตัวสร้างหรือวิธีการในคลาสนี้จะทำให้ nullpointerexception ถูกโยน
เนื่องจาก:
1.5
ผู้เขียน:
Michael McCloskey
ดูเพิ่มเติม:
java.lang.stringbuffer
java.lang.string
สตริงบัฟเฟอร์
ลำดับอักขระที่ปลอดภัยและไม่แน่นอนของเธรด บัฟเฟอร์สตริงเป็นเหมือนสตริง แต่สามารถแก้ไขได้ ในเวลาใดก็ตามมันมีลำดับอักขระบางอย่าง แต่ความยาวและเนื้อหาของลำดับสามารถเปลี่ยนแปลงได้ผ่านการเรียกวิธีการบางอย่าง
สตริงบัฟเฟอร์ปลอดภัยสำหรับการใช้งานหลายเธรด วิธีการจะถูกซิงโครไนซ์ในกรณีที่จำเป็นเพื่อให้การดำเนินการทั้งหมดในอินสแตนซ์ใด ๆ มีพฤติกรรมราวกับว่าพวกเขาเกิดขึ้นในลำดับอนุกรมบางอย่างที่สอดคล้องกับลำดับของการเรียกวิธีการที่ทำโดยแต่ละเธรดแต่ละตัวที่เกี่ยวข้อง
การดำเนินการหลักของ StringBuffer คือวิธีการผนวกและแทรกซึ่งเกินพิกัดเพื่อรับข้อมูลทุกประเภท แต่ละตัวแปลงข้อมูลที่กำหนดเป็นสตริงได้อย่างมีประสิทธิภาพจากนั้นผนวกหรือแทรกอักขระของสตริงนั้นเป็นบัฟเฟอร์สตริง วิธีการภาคผนวกจะเพิ่มอักขระเหล่านี้ในตอนท้ายของบัฟเฟอร์เสมอ วิธีการแทรกเพิ่มอักขระที่จุดที่ระบุ
ตัวอย่างเช่นหาก Z หมายถึงวัตถุบัฟเฟอร์สตริงที่มีเนื้อหาปัจจุบันคือ "เริ่มต้น" ดังนั้นวิธีการเรียก z.append ("le") จะทำให้บัฟเฟอร์สตริงมี "startle" ในขณะที่ z.insert (4, "le") จะเปลี่ยนบัฟเฟอร์สตริงให้มี "starlet"
โดยทั่วไปหากผู้อ้างอิง SB ไปยังอินสแตนซ์ของ StringBuffer ดังนั้น SB.Append (X) จะมีเอฟเฟกต์เช่นเดียวกับ SB.INSERT (SB.Length ()
เมื่อใดก็ตามที่การดำเนินการเกิดขึ้นเกี่ยวข้องกับลำดับต้นทาง (เช่นการผนวกหรือแทรกจากลำดับต้นทาง) คลาสนี้จะซิงโครไนซ์เฉพาะในบัฟเฟอร์สตริงที่ดำเนินการไม่ใช่ในแหล่งที่มา โปรดทราบว่าในขณะที่ StringBuffer ได้รับการออกแบบให้ปลอดภัยในการใช้งานพร้อมกันจากหลายเธรดหากตัวสร้างหรือการต่อท้ายหรือแทรกการดำเนินการผ่านลำดับต้นทางที่ใช้ร่วมกันข้ามเธรดรหัสการโทรต้องตรวจสอบให้แน่ใจว่าการดำเนินการมีมุมมองที่สอดคล้องและไม่เปลี่ยนแปลงของลำดับแหล่งที่มาของระยะเวลาการดำเนินการ สิ่งนี้อาจเป็นที่น่าพอใจโดยผู้โทรที่ถือล็อคระหว่างการโทรของการดำเนินการโดยใช้ลำดับต้นฉบับที่ไม่เปลี่ยนรูปหรือโดยไม่แชร์ลำดับต้นทางข้ามเธรด
บัฟเฟอร์สตริงทุกตัวมีความจุ ตราบใดที่ความยาวของลำดับอักขระที่มีอยู่ในบัฟเฟอร์สตริงไม่เกินความจุก็ไม่จำเป็นต้องจัดสรรอาร์เรย์บัฟเฟอร์ภายในใหม่ หากบัฟเฟอร์ภายในล้นมันจะมีขนาดใหญ่ขึ้นโดยอัตโนมัติ
เว้นแต่จะระบุไว้เป็นอย่างอื่นการผ่านอาร์กิวเมนต์ null ไปยังตัวสร้างหรือวิธีการในคลาสนี้จะทำให้ nullpointerexception ถูกโยน
เมื่อรีลีส JDK 5 คลาสนี้ได้รับการเสริมด้วยคลาสเทียบเท่าที่ออกแบบมาเพื่อใช้งานโดยเธรดเดี่ยว StringBuilder โดยทั่วไปแล้วคลาส StringBuilder ควรใช้ในการตั้งค่านี้เนื่องจากรองรับการดำเนินการเดียวกันทั้งหมด แต่เร็วกว่าเนื่องจากไม่มีการซิงโครไนซ์
เนื่องจาก:
jdk1.0
ผู้เขียน:
Arthur Van Hoff
ดูเพิ่มเติม:
java.lang.stringbuilder
java.lang.string
สรุป Javadoc
จากด้านบนเราจะเห็น:
ทั้ง StringBuffer และ StringBuilder ถือได้ว่าเป็นสตริงตัวแปร
StringBuffer เป็นเธรดที่ปลอดภัยและปรากฏขึ้นก่อนและมีอยู่ใน JDK1.0
StringBuilder ไม่ปลอดภัยและปรากฏในภายหลังและมีอยู่ใน JDK1.5 เท่านั้น
อินเทอร์เฟซของทั้งสองนั้นเหมือนกันทุกประการและ StringBuilder เร็วกว่า
ในความเป็นจริงมันเป็นเรื่องดีที่จะใช้มันตามปกติเพียงรู้จุดเหล่านี้ แต่ฉันยังต้องการดูว่ามันถูกนำไปใช้ในซอร์สโค้ดอย่างไร
รหัสต้นฉบับ
วิธีการบรรลุความปลอดภัยของด้าย
คุณสามารถดูได้จากซอร์สโค้ดที่ทั้งคู่สืบทอดคลาสนามธรรม AbstractStringBuilder
Public Class StringBuffer ขยายบทคัดย่อ AbstractStringBuilder ใช้ java.io.serializable, charsequencepublic คลาสสุดท้าย StringBuilder ขยาย AbstractStringBuilder ใช้ java.io.serializable
จำนวนรหัสไม่ใหญ่มาก StringBuilder440 บรรทัดของรหัส, StringBuffer718 บรรทัดของรหัสและส่วนใหญ่คือ AbstractStringBuilder โดยมีรหัสทั้งหมด 1440 บรรทัด
จากหลายมุมมองเราดูที่รหัสหนึ่งคือสิ่งที่โครงสร้างภายในที่สำคัญบางอย่างมีลักษณะเป็นอย่างไรและอื่น ๆ เป็นวิธีที่ฟังก์ชั่นที่เราใช้โดยทั่วไปจะถูกนำไปใช้ เนื่องจากสตริงไม่เปลี่ยนรูปมันจึงถูกวางไว้ในสระว่ายน้ำคงที่ คาดเดาได้ว่าควรใช้ StringBuilder และ StringBuffer โดยใช้อาร์เรย์ถ่าน
/*** ค่าใช้สำหรับการจัดเก็บอักขระ */ char [] ค่า; /*** จำนวนคือจำนวนอักขระที่ใช้ */ int count;
จะเห็นได้ว่าข้อมูลจะถูกเก็บไว้ด้วยค่าและความยาวจะแสดงด้วยการนับ
มาดูการใช้งานที่แตกต่างกันของวิธีการทั่วไปหลายวิธี
สตริงบัฟเฟอร์
@Override public synchronized stringbuffer supt (string str) {toStringCache = null; super.append (str); คืนสิ่งนี้; } / ** * @throws stringIndExOfBoundSexception {@inheritDoc} * / @Override public synchronized stringbuffer แทรก (int offset, str String) {toStringCache = null; super.insert (ชดเชย, str); คืนสิ่งนี้; } @Override สตริงที่ซิงโครไนซ์สาธารณะ toString () {ถ้า (toStringCache == null) {toStringCache = array.CopyOfRange (ค่า, 0, นับ); } ส่งคืนสตริงใหม่ (ToStringCache, จริง); -สตริง
@Override Public StringBuilder ผนวก (String str) {super.append (str); คืนสิ่งนี้; } / ** * @throws stringIndExOfBoundSexception {@InherItDoc} * / @Override Public StringBuilder แทรก (int Offset, String str) {super.insert (ออฟเซ็ต, str); คืนสิ่งนี้; } @Override สตริงสาธารณะ toString () {// สร้างสำเนาอย่าแชร์อาร์เรย์ส่งคืนสตริงใหม่ (ค่า, 0, นับ); -ดังที่เห็นได้จากรหัสในกรณีส่วนใหญ่ Strinbbuffer เพียงเพิ่มคำหลักที่ซิงโครไนซ์เพื่อความปลอดภัยของเธรด แต่วิธีการ ToString นั้นแตกต่างกันดังนั้นฉันจะพูดถึงเรื่องนี้ในภายหลัง
เริ่มต้นขนาดและวิธีการเติบโต
เนื่องจากเป็นอาร์เรย์จริง ๆ ขนาดและวิธีการเติบโตของอาร์เรย์ที่เริ่มต้นจากนั้นสำคัญมาก มาดูรหัสกันเถอะ
/** * สร้างบัฟเฟอร์สตริงที่ไม่มีอักขระในนั้นและ * ความจุเริ่มต้นที่ 16 อักขระ */ Public StringBuffer () {Super (16); } /** * สร้างตัวสร้างสตริงที่ไม่มีอักขระในนั้นและ * ความจุเริ่มต้นที่ 16 อักขระ */ Public StringBuilder () {super (16); -อย่างที่คุณเห็นตัวสร้างเริ่มต้นทั้งสองนี้ระบุว่าขนาดอาร์เรย์เริ่มต้นคือ 16
ทำไม 16? ฉันไม่เข้าใจ
อะไรคือความกังวลเกี่ยวกับวิธีการเติบโต? ลองมาดูการใช้งานต่อท้าย
Public AbstractStringBuilder ผนวก (String str) {ถ้า (str == null) return uptendNull (); int len = str.length (); ensurecapacityInternal (นับ + len); str.getchars (0, len, ค่า, นับ); นับ += len; คืนสิ่งนี้; } /** * วิธีนี้มีสัญญาเช่นเดียวกับความสามารถในการตรวจสอบ แต่ไม่เคยซิงโครไนซ์ */ โมฆะส่วนตัว ensureCapacityInternal (int minimumcapacity) {// รหัสที่ใส่ใจมากเกินไปถ้า (ขั้นต่ำสุด - ค่า - value.length> 0) ExpandCapacity (ขั้นต่ำสุด); } /** * สิ่งนี้ใช้ความหมายการขยายตัวของความสามารถในการตรวจสอบโดยไม่มีการตรวจสอบขนาด * หรือการซิงโครไนซ์ */ void expandcapacity (int minimumcapacity) {int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity <0) newCapacity = minimumCapacity; if (newCapacity <0) {ถ้า (ขั้นต่ำสุดยอด <0) // ล้นโยน outofMemoryError ใหม่ (); newCapacity = integer.max_value; } value = array.copyof (ค่า, newCapacity); -สามวิธีข้างต้นอธิบายวิธีการขยายกำลังการผลิต
ใส่ความจุปัจจุบัน *2+2
หากความยาวที่เพิ่มขึ้นใหม่มากกว่าค่านี้ให้ตั้งค่าเป็นค่าที่เพิ่มใหม่
ถ้าล้นให้โยน outofmemoryError
การใช้ toString ใน StringBuffer
/*** แคชของค่าสุดท้ายที่ส่งคืนโดย ToString เคลียร์ * เมื่อใดก็ตามที่ StringBuffer ได้รับการแก้ไข */ ตัวถ่านแบบส่วนตัว [] ToStringCache; @Override public synchronized stringbuffer supt (string str) {toStringCache = null; super.append (str); คืนสิ่งนี้; } @Override สตริงที่ซิงโครไนซ์สาธารณะ toString () {ถ้า (toStringCache == null) {toStringCache = array.CopyOfRange (ค่า, 0, นับ); } ส่งคืนสตริงใหม่ (ToStringCache, จริง); -อย่างที่คุณเห็นจะมีการกำหนดอาร์เรย์ toStringCache ทุกครั้งที่ข้อมูลเปลี่ยนไปจะถูกตั้งค่าเป็น NULL เมื่อ toString นำอีกครั้งจากข้อมูลปัจจุบัน
คำหลักชั่วคราวคือการป้องกันไม่ให้อาเรย์นี้เป็นอนุกรม
สรุป
ในความเป็นจริงซอร์สโค้ดของ Java นั้นค่อนข้างง่าย หากคุณสามารถเริ่มต้นด้วยซอร์สโค้ดคุณสามารถเข้าใจหลักการมากมายอย่างลึกซึ้งยิ่งขึ้น บทความนี้แสดงรายการซอร์สบางส่วนและอธิบายความเหมือนและความแตกต่างระหว่าง StringBuffer และ StringBuilder สั้น ๆ เพื่อนที่สนใจสามารถดูด้วยตัวเอง
บทความข้างต้นดูสั้น ๆ ถึงความเหมือนและความแตกต่างระหว่าง StringBuilder และ StringBuffer จากมุมมองซอร์สโค้ด (การวิเคราะห์ที่ครอบคลุม) เป็นเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่ามันจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น