เมื่อเร็ว ๆ นี้เมื่อฉันกำลังมองหางานผู้ตรวจสอบถามคำถามง่ายๆ: "ความแตกต่างระหว่าง StringBuffer และ StringBuilder สถานการณ์แอปพลิเคชันของพวกเขาคืออะไร" คำตอบของบรรณาธิการแบ่งปันกับคุณด้านล่างเพื่อให้ทุกคนสามารถเรียนรู้ได้ในอนาคตเพื่อสร้างบันทึก
ในความเป็นจริงเพียงมองหา Google Master และคุณจะมีคำตอบ: StringBuffer นั้นเทียบเท่ากับวิธีการและฟังก์ชั่นใน StringBuilder แต่วิธีการส่วนใหญ่ใน StringBuffer ใช้คำหลักที่ซิงโครไนซ์สำหรับการปรับเปลี่ยน หากไม่มีการปรับเปลี่ยนนี้ StringBuilder สามารถพิจารณาเธรดที่ไม่ปลอดภัย
เพื่อให้เข้าใจคำตอบข้างต้นได้ดีขึ้นจะเป็นการดีกว่าที่จะเห็นโดยตรงว่าการใช้ซอร์สโค้ดการใช้งานของ StringBuffer และ StringBuilder นั้นสมจริงยิ่งขึ้น ในฐานะโปรแกรมเมอร์ "หากคุณมีคำถามใด ๆ ให้ดูที่ซอร์สโค้ด" เป็นวิธีที่ถูกต้อง แน่นอนฉันสามารถพูดได้อย่างรับผิดชอบคุณต้องมีเงื่อนไข!
ในการใช้งานของ JDK ทั้ง StringBuffer และ StringBuilder ได้รับการสืบทอดมาจาก AbstractStringBuilder สำหรับความปลอดภัยและความปลอดภัยของมัลติเธรดคุณจะมีความเข้าใจคร่าวๆเกี่ยวกับวิธีการซิงโครไนซ์ใน StringBuffer
ที่นี่ฉันจะพูดคุยสั้น ๆ เกี่ยวกับหลักการการใช้งานของ AbstractStringBuilder: เรารู้ว่าการใช้ StringBuffer นั้นไม่มีอะไรมากไปกว่าการปรับปรุงประสิทธิภาพของการเชื่อมต่อสตริงใน Java เพราะถ้าคุณใช้ + โดยตรงสำหรับการเชื่อมต่อสตริง JVM จะสร้างวัตถุหลายสตริงซึ่งจะทำให้เกิดค่าใช้จ่ายบางอย่าง AbstractStringBuilder ใช้อาร์เรย์ถ่านเพื่อบันทึกสตริงที่ต้องผนวก อาร์เรย์ถ่านมีขนาดเริ่มต้น เมื่อความยาวสตริงของสตริงภาคผนวกเกินขีดความสามารถของอาร์เรย์ถ่านปัจจุบันอาร์เรย์ถ่านจะถูกขยายแบบไดนามิกนั่นคือการใช้พื้นที่หน่วยความจำขนาดใหญ่ขึ้นใหม่แล้วคัดลอกอาร์เรย์ถ่านปัจจุบันไปยังตำแหน่งใหม่ เนื่องจากค่าใช้จ่ายของหน่วยความจำที่จัดสรรใหม่และการคัดลอกมีขนาดค่อนข้างใหญ่ทุกครั้งที่คุณใช้พื้นที่หน่วยความจำใหม่ในลักษณะที่พื้นที่หน่วยความจำมีขนาดใหญ่กว่าที่ต้องการในปัจจุบันซึ่งเป็น 2 เท่า
ถัดไปขอให้สนุก!
นี่คือข้อมูลบางส่วนใน Google:
-
StringBuffer เริ่มต้นด้วย JDK 1.0
StringBuilder เริ่มต้นด้วย JDK 1.5
เริ่มต้นจาก JDK 1.5 การดำเนินการเชื่อมต่อ (+) ด้วยตัวแปรสตริงจะถูกใช้ภายในโดย JVM
StringBuilder ถูกนำมาใช้และการดำเนินการนี้ถูกนำไปใช้โดยใช้ StringBuffer
-
เราดูกระบวนการดำเนินการผ่านโปรแกรมง่าย ๆ :
รายการ 1 buffer.java
บัฟเฟอร์คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {สตริง s1 = "aaaaa"; สตริง s2 = "bbbbbb"; สตริง r = null; int i = 3694; r = s1 + i + s2; สำหรับ (int j = 0; i <10; j ++) {r+= "23124"; -ใช้บัฟเฟอร์คำสั่ง javap -c เพื่อดูการใช้งาน bytecode:
แสดงรายการ 2 บัฟเฟอร์คลาส bytecode
รายการที่สอดคล้องกัน 1 และรายการ 2 คำสั่ง LDC ในรายการ 2 โหลดสตริง "AAAA" จากพูลคงที่ไปด้านบนของสแต็กและ ISTORE_1 จัดเก็บ "AAAAA" ในตัวแปร 1 ต่อไปนี้เหมือนกัน Sipush ผลักดันค่าคงที่จำนวนเต็มสั้น ๆ (-32768 ~ 32767) ไปที่ด้านบนของสแต็ก นี่คือค่าคงที่ "3694" สำหรับชุดคำสั่ง Java เพิ่มเติมโปรดตรวจสอบบทความอื่น "ชุดคำสั่ง Java"
ให้เราเห็นโดยตรงว่า 13, 13 ~ 17 เป็นสิ่งใหม่สำหรับวัตถุ StringBuffer และเรียกวิธีการเริ่มต้น 20 ~ 21 คือการกดตัวแปรแรก 1 ไปที่ด้านบนของสแต็กผ่าน Aload_1 ดังที่ได้กล่าวไว้ก่อนหน้านี้ตัวแปร 1 จะถูกใส่ลงในค่าคงที่สตริง "AAAAA" จากนั้นเรียกใช้วิธีการของ StringBuffer ผ่านคำสั่ง invokevirtual เพื่อแยก "AAAAA" เข้าด้วยกัน 24 ~ 30 ต่อไปนี้เหมือนกัน ในที่สุดใน 33 ฟังก์ชั่น toString ของ StringBuffer ถูกเรียกให้รับผลลัพธ์สตริงและเก็บไว้ในตัวแปร 3 ผ่านร้านค้า
เมื่อเราเห็นสิ่งนี้มีคนพูดว่า "เนื่องจาก JVM ใช้ StringBuffer เพื่อเชื่อมต่อสตริงเราไม่จำเป็นต้องใช้ StringBuffer ตัวเองเพียงแค่ใช้"+"Just!" จริงหรือ? ไม่แน่นอน เมื่อคำพูดไป "มีเหตุผลในการดำรงอยู่" ลองดูที่ bytecode ที่สอดคล้องกับลูปที่ตามมาต่อไป
37 ~ 42 เป็นการเตรียมการทั้งหมดก่อนที่จะเข้าสู่วง 37, 38 Set J เป็น 1. 44 ที่นี่ IF_ICMPGE เปรียบเทียบ j กับ 10 ถ้า j มากกว่า 10 มันจะกระโดดโดยตรงไปที่ 73 นั่นคือคำสั่งคืนออกจากฟังก์ชั่น; มิฉะนั้นจะเข้าสู่ลูปนั่นคือไบต์ของ 47 ~ 66 ที่นี่เราต้องดูที่ 47 ถึง 51 เพื่อทราบว่าทำไมเราใช้ StringBuffer ในรหัสของเราเพื่อจัดการการเชื่อมต่อสตริงเพราะทุกครั้งที่เราดำเนินการ "+" การดำเนินการ JVM มีวัตถุสตริงใหม่เพื่อจัดการการเชื่อมต่อสตริงซึ่งจะมีราคาแพงมากเมื่อมีการเชื่อมต่อการเชื่อมต่อสตริงจำนวนมาก