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
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()
və
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:
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";
System.out.println(emojiString.codePoints().count());
System.out.println(emojiString.chars().count());
}
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.Character
primitiv 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:
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:
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
GO TO FULL VERSION