JavaRush /Java Blogu /Random-AZ /Java-da sətirlər (class java.lang.String)
Viacheslav
Səviyyə

Java-da sətirlər (class java.lang.String)

Qrupda dərc edilmişdir

Giriş

Proqramçının yolu mürəkkəb və uzun bir prosesdir. Və əksər hallarda ekranda Hello World-i göstərən bir proqramla başlayır. Java da istisna deyil (bax: Dərs: “Salam Dünya!” Tətbiqi ). Gördüyümüz kimi, mesaj System.out.println("Hello World!"); Java API-dən istifadə etməklə çıxarılır, System.out.println metodu giriş parametri kimi String qəbul edir . Bu tip məlumatlar müzakirə olunacaq.

Simvollar ardıcıllığı kimi string

Əslində, İngilis dilindən tərcümə edilən String bir simdir. Düzdür, String növü mətn sətirini təmsil edir. Mətn sətri nədir? Mətn sətri bir-birini izləyən simvolların bir növ ardıcıl ardıcıllığıdır. Simvol simvoldur. Ardıcıllıq – ardıcıllıq. Beləliklə, bəli, tamamilə düzgündür, String -in tətbiqidir java.lang.CharSequence. Əgər String sinfinin özünə baxsanız, onda onun daxilində simvollar massivindən başqa bir şey yoxdur: Onun kifayət qədər sadə müqaviləsi private final char value[]; var :java.lang.CharSequence
Java-da sətirlər (class java.lang.String) - 1
Elementlərin sayını almaq, müəyyən bir element əldə etmək və elementlər dəstini almaq üçün bir üsulumuz var + bunu qaytaracaq toString metodunun özü) Java 8-də bizə gələn metodları başa düşmək daha maraqlıdır və bu : chars()codePoints() Oracle Təlimliyindən " Primitive Data" Types'ı xatırlayın ki, char single 16-bit Unicode character. Yəni mahiyyətcə char 0-dan 65535-ə qədər olan ədədləri təmsil edən int ölçüsünün (32 bit) yarısı qədər bir növdür (onluq dəyərlərə bax). ASCII cədvəlində ) . Yəni istəsək char-ı int kimi təqdim edə bilərik. Java 8 isə bundan yararlandı. Java-nın 8-ci versiyasından başlayaraq, bizdə IntStream var - primitiv ints ilə işləmək üçün axın. Buna görə də, charSequence-də simvolları və ya kod nöqtələrini təmsil edən IntStream əldə etmək mümkündür. Onlara keçməzdən əvvəl bu yanaşmanın rahatlığını göstərmək üçün bir nümunə görəcəyik. Tutorialspoint online java kompilyatorundan istifadə edək və kodu icra edək:
public static void main(String []args){
        String line = "aaabccdddc";
        System.out.println( line.chars().distinct().count() );
}
İndi bu sadə üsulla bir sıra unikal simvollar əldə edə bilərsiniz.

CodePoints

Beləliklə, simvollar haqqında gördük. İndi bunların hansı kod nöqtələri olduğu aydın deyil. CodePoint konsepsiyası ona görə yarandı ki, Java meydana çıxanda simvolu kodlaşdırmaq üçün 16 bit (yarım int) kifayət edirdi. Buna görə də, java-da char UTF-16 formatında təqdim olunur (“Unicode 88” spesifikasiyası). Daha sonra Unicode 2.0 ortaya çıxdı, onun konsepsiyası simvolu surroqat cüt (2 simvol) kimi təmsil etmək idi. Bu, mümkün dəyərlərin diapazonunu int dəyərinə qədər genişləndirməyə imkan verdi. Ətraflı məlumat üçün stackoverflow-a baxın: " Simvol kod nöqtəsi ilə müqayisə edilirmi? " UTF-16 Xarakter üçün JavaDoc-da da qeyd olunur . Orada, JavaDoc-da deyilir: 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). Bunu standart əlifbalarda çoxaltmaq olduqca çətindir (və bəlkə də qeyri-mümkündür). Amma simvollar hərf və rəqəmlərlə bitmir. Yaponiyada onlar emoji kimi kodlaşdırılması çox çətin olan bir şey tapdılar - ideoqramların və ifadələrin dili. Vikipediyada bununla bağlı maraqlı bir məqalə var: “ Emoji ”. Gəlin bir emoji nümunəsini tapaq, məsələn, bu: “ Emoji Ghost ”. Gördüyümüz kimi, eyni codePoint hətta orada göstərilib (dəyər = U+1F47B). Hexadecimal formatda göstərilir. Onluq rəqəmə çevirsək, 128123 alırıq. Bu, 16 bitdən çox icazə verir (yəni 65535-dən çox). Gəlin onu kopyalayaq:
Java-da sətirlər (class java.lang.String) - 2
Təəssüf ki, JavaRush platforması mətndə belə simvolları dəstəkləmir. Buna görə də, aşağıdakı nümunədə String-ə dəyər daxil etməlisiniz. Beləliklə, indi sadə bir testi başa düşəcəyik:
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
}
Gördüyünüz kimi, bu halda 1 codePoint 2 simvol üçün gedir. Bu sehrdir.

Xarakter

Yuxarıda gördüyümüz kimi Java-da sətirlər simvoldan ibarətdir. İbtidai tip sizə dəyər saxlamağa imkan verir, lakin java.lang.Characterprimitiv tip üzərindəki sarğı bu simvolla çoxlu faydalı işlər görməyə imkan verir. Məsələn, sətri böyük hərflərə çevirə bilərik:
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));
}
Yaxşı, müxtəlif maraqlı şeylər: isAlphabetic(), isLetter(), isSpaceChar(), isDigit(), isUpperCase(), isMirrored()(məsələn, mötərizələr. '(' güzgü şəkli var ')').

Simli Hovuz

Java-da sətirlər dəyişməzdir, yəni sabitdir. Bu, həmçinin java.lang.String sinifinin JavaDoc-da göstərilmişdir . İkincisi, həm də çox vacib olan, sətirləri hərfi olaraq təyin etmək olar:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
Yəni yuxarıda qeyd edildiyi kimi hər hansı sitat gətirilən sətir əslində obyektdir. Və burada sual yaranır - əgər biz sətirlərdən tez-tez istifadə etsək və onlar çox vaxt eyni ola bilirsə (məsələn, “Səhv” və ya “Uğurla” mətni), sətirlərin hər dəfə yaradılmadığına əmin olmaq üçün hər hansı bir yol varmı? Yeri gəlmişkən, bizdə hələ də Xəritələr var, burada açar sətir ola bilər. O zaman biz mütləq eyni sətirlərin fərqli obyektlərə malik ola bilmərik, əks halda obyekti Xəritədən əldə edə bilməyəcəyik. Java tərtibatçıları düşündülər, düşündülər və String Pool ilə gəldilər. Bu, sətirlərin saxlandığı yerdir, onu simli keş adlandıra bilərsiniz. Bütün sətirlərin özləri orada bitmir, ancaq kodda hərfi ilə göstərilən sətirlər. Hovuza özünüz bir xətt əlavə edə bilərsiniz, lakin bu barədə daha sonra. Beləliklə, yaddaşımızda bu keş hardasa var. Ədalətli sual: bu hovuz harada yerləşir? Bunun cavabını stackoverflow-da tapmaq olar: “ Java-nın String sabit hovuzu harada yaşayır, yığın və ya yığın? " O, Heap yaddaşında, xüsusi iş vaxtı sabit hovuz sahəsində yerləşir. Runtime sabit hovuzu virtual maşın tərəfindən metod sahəsindən - Java Virtual Maşın daxilindəki bütün mövzuların daxil ola biləcəyi Heap-də xüsusi bir sahədən sinif və ya interfeys yaradıldıqda ayrılır . String pool bizə nə verir? Bunun bir sıra üstünlükləri var:
  • Eyni tipli obyektlər yaradılmayacaq
  • İstinad əsasında müqayisə, bərabərlər vasitəsilə xarakter-xarakter müqayisəsindən daha sürətlidir
Bəs yaradılmış obyekti bu keşə yerləşdirmək istəsək nə olar? Sonra, xüsusi bir metodumuz var: String.intern Bu üsul String Pool-a sətir əlavə edir. Qeyd etmək lazımdır ki, bu, yalnız massiv şəklində bir növ önbellek deyil (tam ədədlərə gəldikdə). Təcrübə metodu "doğma" olaraq təyin edilmişdir. Bu o deməkdir ki, metodun özü başqa dildə (əsasən C++) həyata keçirilir. Əsas Java metodları vəziyyətində, onlara JVM səviyyəsində müxtəlif digər optimallaşdırmalar tətbiq edilə bilər. Ümumiyyətlə, sehr burada baş verəcək. Təcrübəçilərlə bağlı aşağıdakı postu oxumaq maraqlıdır: https://habr.com/post/79913/#comment_2345814 Və bu yaxşı fikir kimi görünür. Bəs bu bizə necə təsir edəcək? Amma həqiqətən təsiri olacaq)
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal");
    System.out.println(test == test2);
}
Gördüyünüz kimi, xətlər eynidir, lakin nəticə yalan olacaq. Və hamısı ona görə ki, == dəyərə görə deyil, istinada görə müqayisə edir. Və bu belə işləyir:
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test == test2);
}
Sadəcə qeyd edək ki, biz hələ də yeni String hazırlayacağıq. Yəni təcrübəçi bizə keşdən bir String qaytaracaq, lakin keşdə axtardığımız orijinal String təmizləmək üçün atılacaq, çünki ondan başqa heç kim bilmir. Bu, açıq şəkildə lazımsız resurslar istehlakıdır =( Buna görə də, mümkün qədər qəfil və aşkarlanması çətin olan səhvlərdən qaçmaq üçün həmişə bərabərlərdən istifadə edərək sətirləri müqayisə etməlisiniz.
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test.equals(test2));
}
Equals simvol-xarakter sətirlərinin müqayisəsini həyata keçirir.

Birləşdirmə

Xatırladığımız kimi, xətlər əlavə edilə bilər. Və xatırladığımız kimi, simlərimiz dəyişməzdir. Bəs onda necə işləyir? Düzdür, əlavə olunan obyektlərin simvollarından ibarət yeni bir xətt yaradılır. Plus birləşmənin necə işlədiyinə dair milyonlarla versiya var. Bəziləri hər dəfə yeni bir obyektin olacağını, bəziləri isə başqa bir şeyin olacağını düşünür. Ancaq yalnız bir nəfər haqlı ola bilər. Və kimsə javac tərtibçisidir. Onlayn kompilyator xidmətindən istifadə edək və işləyək:
public class HelloWorld {

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

}
İndi bunu zip arxivi kimi saxlayaq, kataloqa çıxaraq və icra edək: javap –c HelloWorld Və burada hər şeyi tapırıq:
Java-da sətirlər (class java.lang.String) - 3
Döngüdə, əlbəttə ki, StringBuilder vasitəsilə birləşməni özünüz etmək daha yaxşıdır. Və bir növ sehrə görə deyil, StringBuilder tsikldən əvvəl yaradılsın və dövrün özündə yalnız əlavə baş verir. Yeri gəlmişkən, burada başqa bir maraqlı məqam da var. Mükəmməl bir məqalə var: “ Java-da String Processing. I hissə: String, StringBuffer, StringBuilder ." Şərhlərdə çoxlu faydalı məlumatlar. Məsələn, müəyyən edilmişdir ki, görünüşü birləşdirərkən new StringBuilder().append()...toString()daxili optimallaşdırma qüvvədədir və defolt olaraq aktivləşdirilmiş -XX:+OptimizeStringConcat seçimi ilə tənzimlənir. daxili - "daxili" kimi tərcümə olunur. JVM bu cür şeyləri xüsusi bir şəkildə idarə edir, onları Native kimi emal edir, yalnız JNI-nin əlavə xərcləri olmadan. Daha çox oxuyun: " HotSpot VM-də daxili üsullar ".

StringBuilder və StringBuffer

Yuxarıda gördüyümüz kimi, StringBuilder çox faydalı bir vasitədir. Sətirlər dəyişməzdir, yəni. dəyişməz. Və mən onu bükmək istəyirəm. Buna görə də bizə kömək etmək üçün bizə 2 sinif verilir: StringBuilder və StringBuffer. İkisi arasındakı əsas fərq StringBuffer-in JDK1.0-da təqdim edilməsidir, StringBuilder isə lazımsız metod sinxronizasiyasının artan yükünü aradan qaldırmaq üçün StringBuffer-in sinxronlaşdırılmamış versiyası kimi java 1.5-də gəldi. Bu siniflərin hər ikisi AbstractStringBuilder - Dəyişən simvol ardıcıllığı abstrakt sinfinin tətbiqləridir. İçəridə bir sıra cazibələr saxlanılır, bu qaydaya uyğun olaraq genişləndirilir: dəyər.uzunluq * 2 + 2. Varsayılan olaraq, StringBuilder-in ölçüsü (tutumu) 16-dır.

Müqayisə edilə bilən

Sətirlər müqayisə edilə bilər, yəni. compareTo metodunu tətbiq edin. Bu, xarakter-xarakter müqayisəsindən istifadə etməklə həyata keçirilir. Maraqlıdır ki, minimum uzunluq iki sətirdən seçilir və onun üzərində bir döngə icra olunur. Buna görə, compareTo ya ən kiçik sətir uzunluğuna qədər ilk uyğun olmayan simvolların int dəyərləri arasındakı fərqi qaytaracaq, ya da bütün simvollar minimum sətir uzunluğu daxilində uyğun gəlirsə, sətir uzunluqları arasındakı fərqi qaytaracaq. Bu müqayisə “leksikoqrafik” adlanır.

Java Strings ilə işləmək

String çox faydalı üsullara malikdir:
Java-da sətirlər (class java.lang.String) - 4
Simlərlə işləmək üçün bir çox tapşırıq var. Məsələn, Coding Bat -da . Kurs kursu da var: " Stringlərdə alqoritmlər ".

Nəticə

Hətta bu sinfin qısa icmalı da çox böyük yer tutur. Və bu hamısı deyil. JPoint 2015 hesabatına baxmağı çox tövsiyə edirəm: Aleksey Şipilev - Catechism java.lang.String
#Viaçeslav
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION