JavaRush /Blog Java /Random-MS /Rentetan dalam Java (kelas java.lang.String)

Rentetan dalam Java (kelas java.lang.String)

Diterbitkan dalam kumpulan

pengenalan

Laluan seorang pengaturcara adalah proses yang kompleks dan panjang. Dan dalam kebanyakan kes ia bermula dengan program yang memaparkan Hello World pada skrin. Java tidak terkecuali (lihat Pelajaran: Aplikasi "Hello World!" ). Seperti yang kita dapat lihat, mesej dikeluarkan menggunakan System.out.println("Hello World!"); Jika anda melihat API Java, kaedah System.out.println mengambil String sebagai parameter input . Jenis data ini akan dibincangkan.

Rentetan sebagai urutan aksara

Sebenarnya, String yang diterjemahkan daripada bahasa Inggeris ialah rentetan. Betul, jenis String mewakili rentetan teks. Apakah rentetan teks? Rentetan teks ialah sejenis urutan aksara yang tersusun mengikut satu sama lain. Simbolnya ialah char. Urutan – urutan. Jadi ya, betul sekali, String ialah pelaksanaan java.lang.CharSequence. Dan jika anda melihat di dalam kelas String itu sendiri, maka di dalamnya tidak ada yang lebih daripada pelbagai aksara: private final char value[]; Ia mempunyai java.lang.CharSequencekontrak yang agak mudah:
Rentetan dalam Java (kelas java.lang.String) - 1
Kami mempunyai kaedah untuk mendapatkan bilangan elemen, mendapatkan elemen tertentu dan mendapatkan satu set elemen + kaedah toString itu sendiri, yang akan mengembalikan ini) Lebih menarik untuk memahami kaedah yang datang kepada kami di Java 8, dan ini adalah : chars()dan codePoints() Ingat kembali daripada Tutorial daripada Oracle “ Primitive Data” Types " bahawa char ialah single 16-bit Unicode character. Iaitu, pada dasarnya char hanyalah jenis separuh saiz int (32 bit) yang mewakili nombor dari 0 hingga 65535 (lihat nilai perpuluhan dalam Jadual ASCII ). Iaitu, jika kita mahu, kita boleh mewakili char sebagai int. Dan Java 8 mengambil kesempatan daripada ini. Bermula dengan versi 8 Java, kami mempunyai IntStream - aliran untuk bekerja dengan int primitif. Oleh itu, dalam charSequence adalah mungkin untuk mendapatkan IntStream yang mewakili sama ada aksara atau codePoints. Sebelum kita beralih kepada mereka, kita akan melihat contoh untuk menunjukkan kemudahan pendekatan ini. Mari gunakan pengkompil java dalam talian Tutorialspoint dan laksanakan kod:
public static void main(String []args){
        String line = "aaabccdddc";
        System.out.println( line.chars().distinct().count() );
}
Kini anda boleh mendapatkan beberapa simbol unik dengan cara mudah ini.

CodePoints

Jadi, kami melihat tentang aksara. Sekarang tidak jelas jenis mata kod ini. Konsep codePoint muncul kerana apabila Java muncul, 16 bit (separuh int) sudah cukup untuk mengekod aksara. Oleh itu, char dalam java diwakili dalam format UTF-16 (spesifikasi "Unicode 88"). Kemudian, Unicode 2.0 muncul, konsepnya adalah untuk mewakili watak sebagai pasangan pengganti (2 aksara). Ini membolehkan kami mengembangkan julat nilai yang mungkin kepada nilai int. Untuk butiran lanjut, lihat stackoverflow: " Membandingkan aksara kepada titik kod? " UTF-16 juga disebut dalam JavaDoc for Character . Di sana, dalam JavaDoc, dikatakan bahawa: Agak 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). sukar (dan mungkin juga mustahil) untuk menghasilkan semula ini dalam abjad standard. Tetapi simbol tidak berakhir dengan huruf dan nombor. Di Jepun mereka datang dengan sesuatu yang sukar untuk dikodkan sebagai emoji - bahasa ideogram dan emotikon. Terdapat artikel menarik tentang ini di Wikipedia: " Emoji ". Mari cari contoh emoji, contohnya ini: “ Emoji Ghost ”. Seperti yang kita dapat lihat, codePoint yang sama ditunjukkan di sana (nilai = U+1F47B). Ia ditunjukkan dalam format heksadesimal. Jika kita menukar kepada nombor perpuluhan, kita mendapat 128123. Ini lebih daripada 16 bit yang dibenarkan (iaitu lebih daripada 65535). Mari salin:
Rentetan dalam Java (kelas java.lang.String) - 2
Malangnya, platform JavaRush tidak menyokong aksara sedemikian dalam teks. Oleh itu, dalam contoh di bawah anda perlu memasukkan nilai ke dalam String. Oleh itu, sekarang kita akan memahami ujian mudah:
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
}
Seperti yang anda lihat, dalam kes ini 1 codePoint digunakan untuk 2 aksara. Inilah keajaibannya.

Perwatakan

Seperti yang kita lihat di atas, Strings dalam Java terdiri daripada char. Jenis primitif membolehkan anda menyimpan nilai, tetapi pembalut java.lang.Characteratas jenis primitif membolehkan anda melakukan banyak perkara berguna dengan simbol ini. Sebagai contoh, kita boleh menukar rentetan kepada huruf besar:
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));
}
Nah, pelbagai perkara menarik: isAlphabetic(), isLetter(), isSpaceChar(), isDigit(), isUpperCase(), isMirrored()(contohnya, kurungan. '(' mempunyai imej cermin ')').

Kolam Rentetan

Rentetan dalam Java tidak boleh berubah, iaitu, tetap. Ini juga ditunjukkan dalam JavaDoc kelas java.lang.String itu sendiri . Kedua, dan juga sangat penting, rentetan boleh ditentukan sebagai literal:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
Iaitu, sebarang rentetan yang dipetik, seperti yang dinyatakan di atas, sebenarnya adalah objek. Dan ini menimbulkan persoalan - jika kita menggunakan rentetan dengan kerap dan ia selalunya boleh sama (contohnya, teks "Ralat" atau "Berjaya"), adakah terdapat cara untuk memastikan rentetan itu tidak dibuat setiap kali? Ngomong-ngomong, kami masih mempunyai Peta, di mana kuncinya boleh menjadi rentetan. Kemudian kita pasti tidak boleh mempunyai rentetan yang sama dengan objek yang berbeza, jika tidak, kita tidak akan dapat mendapatkan objek daripada Peta. Pembangun Java berfikir, berfikir dan menghasilkan String Pool. Ini adalah tempat di mana rentetan disimpan, anda boleh memanggilnya cache rentetan. Tidak semua baris itu sendiri berakhir di sana, tetapi hanya baris yang ditentukan dalam kod dengan literal. Anda boleh menambah baris pada kolam sendiri, tetapi lebih lanjut mengenainya kemudian. Jadi, dalam ingatan kita mempunyai cache ini di suatu tempat. Soalan yang adil: di manakah kolam ini terletak? Jawapan untuk ini boleh didapati di stackoverflow: “ Di manakah kolam pemalar Java's String hidup, timbunan atau timbunan? " Ia terletak dalam memori Heap, dalam kawasan kolam pemalar masa jalan khas. Kumpulan pemalar Runtime diperuntukkan apabila kelas atau antara muka dicipta oleh mesin maya daripada kawasan kaedah - kawasan khas dalam Heap yang semua benang dalam Mesin Maya Java mempunyai akses kepadanya. Apakah yang diberikan oleh kolam String kepada kita? Ini mempunyai beberapa kelebihan:
  • Objek daripada jenis yang sama tidak akan dibuat
  • Perbandingan melalui rujukan adalah lebih pantas daripada perbandingan aksara demi aksara melalui sama
Tetapi bagaimana jika kita mahu meletakkan objek yang dicipta ke dalam cache ini? Kemudian, kami mempunyai kaedah khas: String.intern Kaedah ini menambah rentetan pada Kolam Rentetan. Perlu diingat bahawa ini bukan hanya sejenis cache dalam bentuk tatasusunan (seperti untuk Integer). Kaedah pelatih dinyatakan sebagai "asli". Ini bermakna kaedah itu sendiri dilaksanakan dalam bahasa lain (kebanyakannya C++). Dalam kes kaedah Java asas, pelbagai pengoptimuman lain boleh digunakan pada mereka di peringkat JVM. Secara umum, sihir akan berlaku di sini. Sangat menarik untuk membaca siaran berikut tentang pelatih: https://habr.com/post/79913/#comment_2345814 Dan ia kelihatan seperti idea yang bagus. Tetapi bagaimana ini akan mempengaruhi kita? Tetapi ia benar-benar akan memberi kesan)
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal");
    System.out.println(test == test2);
}
Seperti yang anda lihat, garisan adalah sama, tetapi hasilnya akan palsu. Dan semua kerana == membandingkan bukan dengan nilai, tetapi dengan rujukan. Dan ini adalah cara ia berfungsi:
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test == test2);
}
Hanya ambil perhatian bahawa kami masih akan membuat String baharu. Iaitu, pelatih akan memulangkan kami String daripada cache, tetapi String asal yang kami cari dalam cache akan dibuang keluar untuk pembersihan, kerana tiada orang lain yang tahu tentang dia. Ini jelas merupakan penggunaan sumber yang tidak perlu =( Oleh itu, anda harus sentiasa membandingkan rentetan menggunakan sama untuk mengelakkan ralat yang tiba-tiba dan sukar untuk dikesan sebanyak mungkin.
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test.equals(test2));
}
Equals melakukan perbandingan rentetan aksara demi aksara.

Penyatuan

Seperti yang kita ingat, baris boleh ditambah. Dan seperti yang kita ingat, rentetan kita tidak boleh berubah. Jadi bagaimana ia berfungsi kemudian? Betul, baris baru dicipta, yang terdiri daripada simbol objek yang ditambah. Terdapat sejuta versi cara penggabungan tambah berfungsi. Sesetengah orang berfikir bahawa akan ada objek baru setiap kali, yang lain berpendapat bahawa akan ada sesuatu yang lain. Tetapi hanya seorang sahaja yang mungkin betul. Dan seseorang itu adalah pengkompil javac. Mari gunakan perkhidmatan pengkompil dalam talian dan jalankan:
public class HelloWorld {

    public static void main(String[] args) {
        String helloMessage = "Hello, ";
        String target = "World";
        System.out.println(helloMessage + target);
    }

}
Sekarang mari kita simpan ini sebagai arkib zip, ekstrak ke direktori dan laksanakan: javap –c HelloWorld Dan di sini kita mengetahui segala-galanya:
Rentetan dalam Java (kelas java.lang.String) - 3
Dalam gelung, sudah tentu, adalah lebih baik untuk melakukan penggabungan melalui StringBuilder sendiri. Dan bukan kerana sejenis sihir, tetapi supaya StringBuilder dicipta sebelum kitaran, dan dalam kitaran itu sendiri hanya penambahan berlaku. By the way, ada satu lagi perkara menarik di sini. Terdapat artikel yang sangat baik: " Pemprosesan Rentetan dalam Java. Bahagian I: String, StringBuffer, StringBuilder ." Banyak maklumat berguna dalam komen. Sebagai contoh, dinyatakan bahawa apabila menggabungkan pandangan, new StringBuilder().append()...toString()pengoptimuman intrinsik berkuat kuasa, dikawal oleh pilihan -XX:+OptimizeStringConcat, yang didayakan secara lalai. intrinsik - diterjemahkan sebagai "dalaman". JVM mengendalikan perkara sedemikian dengan cara yang istimewa, memprosesnya sebagai Orang Asli, hanya tanpa kos tambahan JNI. Baca lebih lanjut: " Kaedah Intrinsik dalam HotSpot VM ".

StringBuilder dan StringBuffer

Seperti yang kita lihat di atas, StringBuilder ialah alat yang sangat berguna. Rentetan tidak boleh diubah, i.e. tidak berubah. Dan saya mahu melipatnya. Oleh itu, kami diberi 2 kelas untuk membantu kami: StringBuilder dan StringBuffer. Perbezaan utama antara keduanya ialah StringBuffer telah diperkenalkan dalam JDK1.0, manakala StringBuilder datang dalam java 1.5 sebagai versi StringBuffer yang tidak disegerakkan untuk menghapuskan peningkatan overhed penyegerakan kaedah yang tidak perlu. Kedua-dua kelas ini adalah pelaksanaan kelas abstrak AbstractStringBuilder - Urutan aksara yang boleh diubah. Tatasusunan azimat disimpan di dalam, yang dikembangkan mengikut peraturan: value.length * 2 + 2. Secara lalai, saiz (kapasiti) StringBuilder ialah 16.

Setanding

Rentetan adalah setanding, i.e. melaksanakan kaedah compareTo. Ini dilakukan menggunakan perbandingan watak demi watak. Menariknya, panjang minimum dipilih daripada dua rentetan dan gelung dilaksanakan di atasnya. Oleh itu, compareTo sama ada akan mengembalikan perbezaan antara nilai int aksara pertama yang tidak sepadan sehingga panjang rentetan terkecil, atau mengembalikan perbezaan antara panjang rentetan jika semua aksara sepadan dalam panjang rentetan minimum. Perbandingan ini dipanggil "lexicographical".

Bekerja dengan Java Strings

String mempunyai banyak kaedah berguna:
Rentetan dalam Java (kelas java.lang.String) - 4
Terdapat banyak tugas untuk bekerja dengan rentetan. Contohnya, pada Coding Bat . Terdapat juga kursus mengenai coursera: " Algoritma pada Rentetan ".

Kesimpulan

Malah gambaran keseluruhan ringkas kelas ini menggunakan jumlah ruang yang mengagumkan. Dan bukan itu sahaja. Saya sangat mengesyorkan menonton laporan dari JPoint 2015: Alexey Shipilev - Catechism java.lang.String
#Viacheslav
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION