การแนะนำ
เส้นทางของโปรแกรมเมอร์เป็นกระบวนการที่ซับซ้อนและยาวนาน และโดยส่วนใหญ่แล้วจะเริ่มต้นด้วยโปรแกรมที่แสดง Hello World บนหน้าจอ Java ก็ไม่มีข้อยกเว้น (ดูบทเรียน:
แอปพลิเคชัน "Hello World!" ) ดังที่เราเห็น ข้อความจะถูกส่งออกโดยใช้
System.out.println("Hello World!");
หากคุณดูที่ Java API เมธอด
System.out.printlnจะใช้
String เป็นพารามิเตอร์ อินพุต เราจะหารือเกี่ยวกับข้อมูลประเภทนี้
สตริงเป็นลำดับของอักขระ
จริงๆ แล้ว
Stringที่แปลจากภาษาอังกฤษคือสตริง ถูกต้อง ประเภทสตริงแสดงถึงสตริงข้อความ สตริงข้อความคืออะไร? สตริงข้อความคือลำดับอักขระบางประเภทที่ต่อกัน สัญลักษณ์คือถ่าน ลำดับ – ลำดับ ใช่แล้ว ถูกต้องอย่างแน่นอน String เป็นการนำไปใช้ของ
java.lang.CharSequence
. และถ้าคุณดูภายในคลาส String ข้างในนั้นก็ไม่มีอะไรมากไปกว่าอาร์เรย์ของตัวอักษร:
private final char value[];
มันมี
java.lang.CharSequence
สัญญาที่ค่อนข้างง่าย:
เรามีวิธีการรับจำนวนองค์ประกอบ, รับองค์ประกอบเฉพาะและรับชุดองค์ประกอบ + เมธอด toString เองซึ่งจะส่งคืนสิ่งนี้) การทำความเข้าใจวิธีการที่มาหาเราใน Java 8 นั้นน่าสนใจกว่าและนี่คือ :
chars()
และ
codePoints()
เรียกคืนจาก Tutorial จาก Oracle “
Primitive Data” ประเภท " char ที่เป็น
single 16-bit Unicode character
. กล่าวคือ โดยพื้นฐานแล้ว char เป็นเพียงประเภทครึ่งหนึ่งของขนาด int (32 บิต) ที่แสดงตัวเลขตั้งแต่ 0 ถึง 65535 (ดูค่าทศนิยม ใน
ตาราง ASCII ) นั่นคือหากเราต้องการ เราก็สามารถแสดง char เป็น int ได้ และ Java 8 ก็ใช้ประโยชน์จากสิ่งนี้ เริ่มต้นด้วย Java เวอร์ชัน 8 เรามี
IntStream - สตรีมสำหรับการทำงานกับ ints ดั้งเดิม ดังนั้นใน charSequence จึงเป็นไปได้ที่จะรับ IntStream ที่แสดงถึงตัวอักษรหรือ codePoints ก่อนที่เราจะไปยังเรื่องเหล่านั้น เราจะเห็นตัวอย่างเพื่อแสดงให้เห็นถึงความสะดวกของแนวทางนี้ ลองใช้
คอมไพเลอร์ Java ออนไลน์ของ Tutorialspointและรันโค้ด:
public static void main(String []args){
String line = "aaabccdddc";
System.out.println( line.chars().distinct().count() );
}
ตอนนี้คุณสามารถรับสัญลักษณ์พิเศษจำนวนหนึ่งด้วยวิธีง่ายๆ นี้
รหัสพอยต์
ดังนั้นเราจึงเห็นเกี่ยวกับตัวอักษร ตอนนี้ยังไม่ชัดเจนว่าจุดรหัสเหล่านี้คืออะไร แนวคิดของ codePoint ปรากฏขึ้นเนื่องจากเมื่อ Java ปรากฏขึ้น 16 บิต (ครึ่ง int) ก็เพียงพอที่จะเข้ารหัสอักขระได้ ดังนั้น char ใน java จึงแสดงในรูปแบบ UTF-16 (ข้อกำหนด "Unicode 88") ต่อมา Unicode 2.0 ปรากฏขึ้น โดยมีแนวคิดในการแสดงอักขระเป็นคู่ตัวแทน (2 อักขระ) สิ่งนี้ทำให้เราสามารถขยายช่วงของค่าที่เป็นไปได้ให้เป็นค่า int สำหรับรายละเอียดเพิ่มเติม โปรดดูที่ stackoverflow: "
กำลังเปรียบเทียบอักขระกับโค้ดพอยต์ใช่หรือไม่ " UTF- 16 ยังถูกกล่าวถึงใน JavaDoc for
Character ใน JavaDoc กล่าวกันว่า: มัน
In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF).
ค่อนข้างยาก (และอาจเป็นไปไม่ได้ด้วยซ้ำ) ที่จะทำซ้ำสิ่งนี้ด้วยตัวอักษรมาตรฐาน แต่สัญลักษณ์ไม่ได้ลงท้ายด้วยตัวอักษรและตัวเลข ในญี่ปุ่น พวกเขาคิดค้นสิ่งที่เข้ารหัสได้ยากในรูปแบบอิโมจิ นั่นคือภาษาของรูปสัญลักษณ์และอีโมติคอน มีบทความที่น่าสนใจเกี่ยวกับเรื่องนี้ใน Wikipedia: “
Emoji ” มาดูตัวอย่างอิโมจิกัน เช่น “
Emoji Ghost ” ดังที่เราเห็น codePoint เดียวกันนั้นถูกระบุอยู่ที่นั่นด้วยซ้ำ (ค่า = U+1F47B) ระบุไว้ในรูปแบบเลขฐานสิบหก หากเราแปลงเป็นเลขทศนิยม เราจะได้ 128123 ซึ่งอนุญาตให้ใช้ได้มากกว่า 16 บิต (เช่น มากกว่า 65535) มาคัดลอกกัน:
น่าเสียดายที่แพลตฟอร์ม JavaRush ไม่รองรับอักขระดังกล่าวในข้อความ ดังนั้น ในตัวอย่างด้านล่าง คุณจะต้องแทรกค่าลงใน String ดังนั้นตอนนี้เราจะมาทำความเข้าใจกับการทดสอบง่ายๆ:
public static void main(String []args){
String emojiString = "Вставте сюда эмоджи через ctrl+v";
System.out.println(emojiString.codePoints().count());
System.out.println(emojiString.chars().count());
}
อย่างที่คุณเห็น ในกรณีนี้ 1 codePoint ใช้ได้ 2 ตัวอักษร นี่คือความมหัศจรรย์
อักขระ
ดังที่เราเห็นข้างต้น Strings ใน Java ประกอบด้วยอักขระ ชนิดดั้งเดิมช่วยให้คุณสามารถเก็บค่าได้ แต่ตัวหุ้ม
java.lang.Character
ทับชนิดดั้งเดิมช่วยให้คุณสามารถทำสิ่งที่มีประโยชน์มากมายด้วยสัญลักษณ์นี้ ตัวอย่างเช่น เราสามารถแปลงสตริงเป็นตัวพิมพ์ใหญ่:
public static void main(String[] args) {
String line = "организация объединённых наций";
char[] chars = line.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (i == 0 || chars[i - 1] == ' ') {
chars[i] = Character.toUpperCase(chars[i]);
}
}
System.out.println(new String(chars));
}
สิ่งที่น่าสนใจต่างๆ:
isAlphabetic()
,
isLetter()
,
isSpaceChar()
,
isDigit()
,
isUpperCase()
,
isMirrored()
(เช่น วงเล็บ '(' มีภาพสะท้อน ')')
สตริงพูล
สตริงใน Java นั้นไม่เปลี่ยนรูป กล่าวคือ คงที่ สิ่งนี้ยังระบุไว้ใน JavaDoc ของ คลาส
java.lang.String อีกด้วย ประการที่สอง และที่สำคัญมากคือ สามารถระบุสตริงเป็นตัวอักษรได้:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
นั่นคือ สตริงที่ยกมาใดๆ ตามที่ระบุไว้ข้างต้น จริงๆ แล้วเป็นอ็อบเจ็กต์ และสิ่งนี้ทำให้เกิดคำถาม - หากเราใช้สตริงบ่อยมากและสตริงเหล่านั้นมักจะเหมือนกัน (เช่น ข้อความ "ผิดพลาด" หรือ "สำเร็จ") มีวิธีใดที่จะแน่ใจได้ว่าสตริงจะไม่ถูกสร้างขึ้นทุกครั้งหรือไม่ อย่างไรก็ตาม เรายังมี Maps อยู่ โดยที่กุญแจอาจเป็นสตริงได้ ถ้าอย่างนั้นเราไม่สามารถมีสตริงเดียวกันเป็นวัตถุที่แตกต่างกันได้อย่างแน่นอน ไม่เช่นนั้นเราจะไม่สามารถรับวัตถุจากแผนที่ได้ นักพัฒนา Java คิด คิด และเกิด String Poolขึ้นมา นี่คือสถานที่จัดเก็บสตริง คุณสามารถเรียกมันว่าแคชสตริงได้ ไม่ใช่ทุกบรรทัดที่จะจบลงที่นั่น แต่มีเพียงบรรทัดที่ระบุในโค้ดด้วยตัวอักษรเท่านั้น คุณสามารถเพิ่มบรรทัดลงในพูลได้ด้วยตัวเอง แต่จะเพิ่มเติมในภายหลัง ดังนั้น ในความทรงจำ เรามีแคชนี้อยู่ที่ไหนสักแห่ง คำถามที่ยุติธรรม: สระว่ายน้ำนี้ตั้งอยู่ที่ไหน? คำตอบสำหรับเรื่องนี้สามารถพบได้ใน stackoverflow: “
String พูลคงที่ของ Java อยู่ที่ไหน ฮีปหรือสแต็ก? " ตั้งอยู่ในหน่วยความจำฮีป ในพื้นที่พูลคงที่รันไทม์พิเศษ พูลคงที่รันไทม์ได้รับการจัดสรรเมื่อมีการสร้างคลาสหรืออินเทอร์เฟซโดยเครื่องเสมือนจาก
พื้นที่วิธีการซึ่งเป็นพื้นที่พิเศษในฮีปที่เธรดทั้งหมดภายใน Java Virtual Machine สามารถเข้าถึงได้ String pool ให้อะไรเราบ้าง? สิ่งนี้มีข้อดีหลายประการ:
- วัตถุประเภทเดียวกันจะไม่ถูกสร้างขึ้น
- การเปรียบเทียบโดยการอ้างอิงเร็วกว่าการเปรียบเทียบแบบอักขระต่ออักขระโดยใช้ค่าเท่ากัน
แต่ถ้าเราต้องการใส่วัตถุที่สร้างขึ้นลงในแคชนี้ล่ะ? จากนั้น เรามีเมธอดพิเศษ:
String.intern เมธอดนี้จะเพิ่มสตริงใน String Pool เป็นที่น่าสังเกตว่านี่ไม่ใช่แค่แคชบางประเภทในรูปแบบของอาร์เรย์ (สำหรับจำนวนเต็ม) วิธีการฝึกงานระบุเป็น "เนทีฟ" ซึ่งหมายความว่าวิธีการนั้นถูกนำไปใช้ในภาษาอื่น (ส่วนใหญ่เป็น C ++) ในกรณีของวิธีการ Java พื้นฐาน สามารถใช้การปรับให้เหมาะสมอื่น ๆ มากมายในระดับ JVM โดยทั่วไปแล้วเวทมนตร์จะเกิดขึ้นที่นี่ การอ่านโพสต์เกี่ยวกับการฝึกงานต่อไปนี้เป็นเรื่องน่าสนใจ:
https://habr.com/post/79913/#comment_2345814 และดูเหมือนว่าจะเป็นความคิดที่ดี แต่สิ่งนี้จะส่งผลต่อเราอย่างไร? แต่มันจะมีผลกระทบจริงๆ)
public static void main(String[] args) {
String test = "literal";
String test2 = new String("literal");
System.out.println(test == test2);
}
อย่างที่คุณเห็น เส้นเหมือนกัน แต่ผลลัพธ์จะเป็นเท็จ และทั้งหมดเป็นเพราะ == เปรียบเทียบไม่ใช่ตามค่า แต่โดยการอ้างอิง และนี่คือวิธีการทำงาน:
public static void main(String[] args) {
String test = "literal";
String test2 = new String("literal").intern();
System.out.println(test == test2);
}
โปรดทราบว่าเราจะยังคงสร้าง String ใหม่ นั่นคือนักศึกษาฝึกงานจะส่งสตริงกลับมาให้เราจากแคช แต่สตริงดั้งเดิมที่เราค้นหาในแคชจะถูกโยนออกไปเพื่อทำความสะอาดเพราะ ไม่มีใครรู้เกี่ยวกับเขาอีก นี่เป็นการใช้ทรัพยากรโดยไม่จำเป็นอย่างชัดเจน =( ดังนั้น คุณควรเปรียบเทียบสตริงโดยใช้เท่ากับเสมอ เพื่อหลีกเลี่ยงการตรวจจับข้อผิดพลาดอย่างกะทันหันและยากให้มากที่สุด
public static void main(String[] args) {
String test = "literal";
String test2 = new String("literal").intern();
System.out.println(test.equals(test2));
}
เท่ากับดำเนินการเปรียบเทียบสตริงอักขระต่ออักขระ
การต่อข้อมูล
อย่างที่เราจำได้ สามารถเพิ่มบรรทัดได้ และอย่างที่เราจำได้ สายของเราไม่เปลี่ยนรูป แล้วมันทำงานยังไงล่ะ? ถูกต้อง บรรทัดใหม่จะถูกสร้างขึ้น ซึ่งประกอบด้วยสัญลักษณ์ของวัตถุที่กำลังเพิ่ม มีวิธีการบวกต่อข้อมูลหลายล้านเวอร์ชัน บางคนคิดว่าจะมีของใหม่ทุกครั้ง บางคนคิดว่าจะมีอย่างอื่นอีก แต่อาจมีเพียงคนเดียวเท่านั้นที่ถูก และคนนั้นคือคอมไพเลอร์ javac มาใช้ บริการ
คอมไพเลอร์ออนไลน์แล้วรัน:
public class HelloWorld {
public static void main(String[] args) {
String helloMessage = "Hello, ";
String target = "World";
System.out.println(helloMessage + target);
}
}
ตอนนี้มาบันทึกสิ่งนี้เป็นไฟล์ zip แยกมันไปยังไดเร็กทอรีแล้วดำเนินการ:
javap –c HelloWorld
และที่นี่เราจะค้นหาทุกสิ่ง:
แน่นอนว่าการต่อข้อมูลผ่าน StringBuilder ด้วยตัวเองจะดีกว่า และไม่ใช่เพราะเวทย์มนตร์บางชนิด แต่เพื่อให้ StringBuilder ถูกสร้างขึ้นก่อนรอบและในวงจรนั้นจะมีการต่อท้ายเท่านั้น ยังไงก็ตามยังมีอีกสิ่งที่น่าสนใจที่นี่ มีบทความที่ยอดเยี่ยม: “
การประมวลผลสตริงใน Java ส่วนที่ 1: String, StringBuffer, StringBuilder " ข้อมูลที่เป็นประโยชน์มากมายในความคิดเห็น ตัวอย่างเช่น มีการระบุว่าเมื่อเชื่อมต่อมุมมอง
new StringBuilder().append()...toString()
การเพิ่มประสิทธิภาพที่แท้จริงจะมีผล ควบคุมโดยอ็อพชัน -XX:+OptimizeStringConcat ซึ่งเปิดใช้งานโดยดีฟอลต์ ภายใน - แปลว่า "ภายใน" JVM จัดการสิ่งเหล่านี้ด้วยวิธีพิเศษ โดยประมวลผลเป็น Native โดยไม่มีค่าใช้จ่ายเพิ่มเติมของ JNI เท่านั้น อ่านเพิ่มเติม: "
วิธีการที่แท้จริงใน HotSpot VM "
StringBuilder และ StringBuffer
ดังที่เราเห็นข้างต้น StringBuilder เป็นเครื่องมือที่มีประโยชน์มาก สตริงไม่เปลี่ยนรูป กล่าวคือ ไม่เปลี่ยนรูป และฉันต้องการพับมัน ดังนั้นเราจึงได้รับ 2 คลาสเพื่อช่วยเรา: StringBuilder และ StringBuffer ข้อแตกต่างที่สำคัญระหว่างทั้งสองคือ StringBuffer เปิดตัวใน JDK1.0 ในขณะที่ StringBuilder มาใน java 1.5 ในฐานะ StringBuffer เวอร์ชันที่ไม่ซิงโครไนซ์ เพื่อกำจัดค่าใช้จ่ายที่เพิ่มขึ้นของการซิงโครไนซ์เมธอดที่ไม่จำเป็น ทั้งสองคลาสนี้เป็นการใช้งานของคลาสนามธรรม AbstractStringBuilder - ลำดับอักขระที่ไม่แน่นอน อาร์เรย์ของเครื่องรางจะถูกเก็บไว้ภายใน ซึ่งขยายตามกฎ: value.length * 2 + 2 โดยค่าเริ่มต้น ขนาด (ความจุ) ของ StringBuilder คือ 16
เปรียบเทียบได้
สตริงสามารถเปรียบเทียบได้เช่น ใช้เมธอด comparisonTo ทำได้โดยใช้การเปรียบเทียบอักขระต่ออักขระ สิ่งที่น่าสนใจก็คือ ความยาวขั้นต่ำจะถูกเลือกจากสองสาย และมีการวนซ้ำทับมัน ดังนั้น CompareTo จะส่งคืนความแตกต่างระหว่างค่า int ของอักขระที่ไม่ตรงกันตัวแรกจนถึงความยาวสตริงที่เล็กที่สุด หรือส่งคืนความแตกต่างระหว่างความยาวสตริงหากอักขระทั้งหมดตรงกันภายในความยาวสตริงขั้นต่ำ การเปรียบเทียบนี้เรียกว่า "พจนานุกรม"
การทำงานกับสตริง Java
String มีวิธีการที่มีประโยชน์มากมาย:
มีงานมากมายสำหรับการทำงานกับสตริง ตัวอย่างเช่น บน
Coding Bat นอกจากนี้ยังมีหลักสูตรเกี่ยวกับหลักสูตร: "
Algorithms on Strings "
บทสรุป
แม้แต่ภาพรวมโดยย่อของคลาสนี้ก็ยังใช้พื้นที่จำนวนมหาศาล และนั่นไม่ใช่ทั้งหมด ฉันขอแนะนำให้ดูรายงานจาก JPoint 2015: Alexey Shipilev - Catechism java.lang.String
#เวียเชสลาฟ
GO TO FULL VERSION