JavaRush /จาวาบล็อก /Random-TH /สตริงใน Java (คลาส java.lang.String)
Viacheslav
ระดับ

สตริงใน Java (คลาส java.lang.String)

เผยแพร่ในกลุ่ม

การแนะนำ

เส้นทางของโปรแกรมเมอร์เป็นกระบวนการที่ซับซ้อนและยาวนาน และโดยส่วนใหญ่แล้วจะเริ่มต้นด้วยโปรแกรมที่แสดง 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สัญญาที่ค่อนข้างง่าย:
สตริงใน Java (คลาส java.lang.String) - 1
เรามีวิธีการรับจำนวนองค์ประกอบ, รับองค์ประกอบเฉพาะและรับชุดองค์ประกอบ + เมธอด 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) มาคัดลอกกัน:
สตริงใน Java (คลาส java.lang.String) - 2
น่าเสียดายที่แพลตฟอร์ม JavaRush ไม่รองรับอักขระดังกล่าวในข้อความ ดังนั้น ในตัวอย่างด้านล่าง คุณจะต้องแทรกค่าลงใน String ดังนั้นตอนนี้เราจะมาทำความเข้าใจกับการทดสอบง่ายๆ:
public static void main(String []args){
	    String emojiString = "Вставте сюда эмоджи через ctrl+v";
	    //На один emojiString приходится 2 чара (т.к. не влезает в 16 бит)
	    System.out.println(emojiString.codePoints().count()); //1
	    System.out.println(emojiString.chars().count()); //2
}
อย่างที่คุณเห็น ในกรณีนี้ 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 และที่นี่เราจะค้นหาทุกสิ่ง:
สตริงใน Java (คลาส java.lang.String) - 3
แน่นอนว่าการต่อข้อมูลผ่าน 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 มีวิธีการที่มีประโยชน์มากมาย:
สตริงใน Java (คลาส java.lang.String) - 4
มีงานมากมายสำหรับการทำงานกับสตริง ตัวอย่างเช่น บนCoding Bat นอกจากนี้ยังมีหลักสูตรเกี่ยวกับหลักสูตร: " Algorithms on Strings "

บทสรุป

แม้แต่ภาพรวมโดยย่อของคลาสนี้ก็ยังใช้พื้นที่จำนวนมหาศาล และนั่นไม่ใช่ทั้งหมด ฉันขอแนะนำให้ดูรายงานจาก JPoint 2015: Alexey Shipilev - Catechism java.lang.String
#เวียเชสลาฟ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION