ทำไมใน Java คุณสามารถเพิ่ม Strings ด้วยตัวดำเนินการ + เมื่อ String เป็นคลาส? ในString.java
รหัสฉันไม่พบการใช้งานสำหรับผู้ประกอบการนี้ แนวคิดนี้ละเมิดการวางวัตถุหรือไม่?
ทำไมใน Java คุณสามารถเพิ่ม Strings ด้วยตัวดำเนินการ + เมื่อ String เป็นคลาส? ในString.java
รหัสฉันไม่พบการใช้งานสำหรับผู้ประกอบการนี้ แนวคิดนี้ละเมิดการวางวัตถุหรือไม่?
คำตอบ:
ลองดูนิพจน์ง่าย ๆ ต่อไปนี้ใน Java
int x=15;
String temp="x = "+x;
คอมไพเลอร์แปลง"x = "+x;
เป็นStringBuilder
ภายในและใช้.append(int)
เพื่อ "เพิ่ม" จำนวนเต็มสตริง
ประเภทใด ๆ อาจถูกแปลงเป็นประเภท String โดยการแปลงสตริง
ค่า x ของชนิดดั้งเดิม T ถูกแปลงเป็นค่าอ้างอิงก่อนโดยให้เป็นอาร์กิวเมนต์สำหรับนิพจน์การสร้างอินสแตนซ์คลาสที่เหมาะสม (§15.9):
- ถ้า T เป็นบูลีนให้ใช้บูลีนใหม่ (x)
- ถ้า T เป็นตัวอักษรให้ใช้ตัวละครใหม่ (x)
- ถ้า T เป็นไบต์สั้นหรือ int ให้ใช้จำนวนเต็มใหม่ (x)
- ถ้า T ยาวให้ใช้ Long (x) ใหม่
- ถ้า T คือ float ให้ใช้ Float ใหม่ (x)
- หาก T เป็นสองเท่าให้ใช้ Double ใหม่ (x)
ค่าอ้างอิงนี้จะถูกแปลงเป็นประเภท String โดยการแปลงสตริง
ตอนนี้ต้องพิจารณาเฉพาะค่าอ้างอิงเท่านั้น:
- หากการอ้างอิงเป็นโมฆะมันจะถูกแปลงเป็นสตริง "null" (อักขระ ASCII สี่ตัว n, u, l, l)
- มิฉะนั้นการแปลงจะดำเนินการราวกับว่าโดยการเรียกใช้วิธีการ toString ของวัตถุที่อ้างอิงโดยไม่มีข้อโต้แย้ง; แต่ถ้าผลลัพธ์ของการเรียกใช้เมธอด toString เป็นโมฆะจะใช้สตริง "null" แทน
วิธีการ toString ถูกกำหนดโดยวัตถุคลาสดั้งเดิม (§4.3.2) หลายคลาสจะแทนที่มันโดยเฉพาะ Boolean, Character, Integer, Long, Float, Double และ String
ดู§5.4สำหรับรายละเอียดของบริบทการแปลงสตริง
การปรับให้เหมาะสมของสตริงการต่อข้อมูล: การดำเนินการอาจเลือกที่จะทำการแปลงและการต่อข้อมูลในขั้นตอนเดียวเพื่อหลีกเลี่ยงการสร้างแล้วละทิ้งวัตถุสตริงกลาง เพื่อเพิ่มประสิทธิภาพของการต่อสตริงซ้ำซ้ำคอมไพเลอร์ Java อาจใช้คลาส StringBuffer หรือเทคนิคที่คล้ายกันเพื่อลดจำนวนของวัตถุสตริงกลางที่สร้างขึ้นโดยการประเมินผลของการแสดงออก
สำหรับชนิดดั้งเดิมการใช้งานอาจปรับการสร้างวัตถุห่อหุ้มให้เหมาะสมโดยการแปลงจากชนิดดั้งเดิมเป็นสตริงโดยตรง
เวอร์ชันที่ปรับปรุงแล้วจะไม่ทำการแปลงสตริงแบบเต็มก่อน
นี่เป็นภาพประกอบที่ดีของเวอร์ชันที่ปรับให้เหมาะสมซึ่งคอมไพเลอร์ใช้ถึงแม้ว่าจะไม่มีการแปลงค่าดั้งเดิมซึ่งคุณสามารถเห็นคอมไพเลอร์เปลี่ยนสิ่งต่าง ๆ ให้เป็น StringBuilder ในพื้นหลัง:
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
รหัส java นี้:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
สร้างสิ่งนี้ - ดูว่ารูปแบบการต่อข้อมูลสองแบบนำไปสู่โหมดไบต์เดียวกันมากอย่างไร:
L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 4
L4
LINENUMBER 27 L4
RETURN
ดูตัวอย่างด้านบนและวิธีการสร้างรหัสไบต์ตามรหัสแหล่งที่มาในตัวอย่างที่กำหนดคุณจะสามารถสังเกตเห็นว่าคอมไพเลอร์ได้ทำการแปลงข้อความต่อไปนี้ภายใน
cip+ciop;
เข้าไป
new StringBuilder(cip).append(ciop).toString();
กล่าวอีกนัยหนึ่งตัวดำเนินการ+
ในการต่อสตริงเป็นชวเลขอย่างมีประสิทธิภาพสำหรับStringBuilder
สำนวนverbose ที่มากขึ้น
มันเป็นคุณสมบัติของคอมไพเลอร์ Java ที่ตรวจสอบตัวถูกดำเนินการของ+
ผู้ประกอบการ และตามตัวถูกดำเนินการมันสร้างรหัสไบต์:
นี่คือสิ่งที่ Java spec บอก :
ตัวดำเนินการ + และ
-
เรียกว่าตัวดำเนินการเสริม การเพิ่มการแสดงออก: การเพิ่มการแสดงออกการบวกการแสดงออกและการคูณการแสดงออกการบวกการแสดงออก - การคูณการแสดงออกผู้ประกอบการสารเติมแต่งมีความสำคัญเดียวกันและมีความสัมพันธ์ทางด้านซ้าย syntactically (พวกเขากลุ่มจากซ้ายไปขวา) หากชนิดของตัวถูกดำเนินการของตัว
+
ดำเนินการคือString
การดำเนินการคือการต่อสายอักขระมิฉะนั้นชนิดของตัวถูกดำเนินการแต่ละตัวของตัวดำเนิน
+
การจะต้องเป็นชนิดที่สามารถแปลงได้ (§5.1.8) เป็นชนิดตัวเลขดั้งเดิมหรือเกิดข้อผิดพลาดในการคอมไพล์เวลาในทุกกรณีประเภทของตัวถูกดำเนินการของตัวดำเนินการไบนารี
-
แต่ละประเภทจะต้องเป็นประเภทที่สามารถแปลงได้ (§5.1.8) เป็นประเภทตัวเลขดั้งเดิมหรือเกิดข้อผิดพลาดในการรวบรวมเวลา
String class จะแทนที่โอเปอเรเตอร์ + อย่างไร
มันไม่ได้ คอมไพเลอร์ทำมัน คอมไพเลอร์พูดอย่างหนักเกินตัวดำเนินการ + สำหรับตัวถูกดำเนินการสตริง
ก่อนอื่น (+) ถูกโหลดมากเกินไปจะไม่ถูกเขียนทับ
ภาษา Java จัดเตรียมการสนับสนุนพิเศษสำหรับตัวดำเนินการต่อสตริง (+) ซึ่งโอเวอร์โหลดสำหรับวัตถุ Java Strings
ถ้าตัวถูกดำเนินการทางด้านซ้ายมือเป็นสตริงมันจะทำงานเป็นการต่อข้อมูล
ถ้าตัวถูกดำเนินการทางด้านซ้ายมือเป็นจำนวนเต็มมันจะทำงานเป็นตัวดำเนินการเพิ่มเติม
int
และจากนั้นจะใช้กฎปกติของ Java
ภาษา Java จัดเตรียมการสนับสนุนพิเศษสำหรับตัวดำเนินการต่อสตริง (+) และสำหรับการแปลงวัตถุอื่นเป็นสตริง การต่อข้อมูลสตริงจะดำเนินการผ่านคลาสStringBuilder
(หรือStringBuffer
) และappend
วิธีการ
ความหมายของ+
โอเปอเรเตอร์เมื่อใช้กับString
ถูกกำหนดโดยภาษาตามที่ทุกคนเขียนไว้แล้ว เนื่องจากคุณดูเหมือนจะไม่พบสิ่งที่น่าเชื่อถือเพียงพอให้พิจารณาสิ่งนี้:
Ints, floats และ doubles ทั้งหมดมีการแทนเลขฐานสองที่แตกต่างกัน, และดังนั้นการเพิ่มสอง ints เป็นการดำเนินการที่แตกต่างกัน, ในแง่ของการจัดการบิต, มากกว่าการเพิ่มสอง float: สำหรับ ints คุณสามารถเพิ่มทีละบิต, สำหรับการลอยคุณต้องจัดการกับ mantissas และ exponents แยกต่างหาก
ตามหลักการแล้ว "การเพิ่ม" ขึ้นอยู่กับลักษณะของวัตถุที่ถูก "เพิ่ม" Java กำหนดไว้สำหรับ Strings รวมถึง ints และ float (longs, doubles, ... )
+
ผู้ประกอบการมักจะถูกแทนที่ด้วยStringBuilder
ที่รวบรวมเวลา ตรวจสอบคำตอบนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนั้น
+
ตัวดำเนินการไม่ได้ถูกแทนที่ด้วยStringBuilder
หรือไม่?
+
) เป็นคุณสมบัติภาษาของ Java