JavaRush /Java блогу /Random-KY /Java тилиндеги саптар (class java.lang.String)
Viacheslav
Деңгээл

Java тилиндеги саптар (class java.lang.String)

Группада жарыяланган

Киришүү

Программисттин жолу татаал жана узак процесс. Ал эми көпчүлүк учурларда ал экранда Hello World көрсөтүүчү программа менен башталат. Java да өзгөчө эмес (Сабак: "Салам дүйнө!" Тиркемесин караңыз ). Көрүнүп тургандай, билдирүү Java API аркылуу чыгарылат System.out.println("Hello World!"); , эгер сиз Java APIди карасаңыз, System.out.println ыкмасы String киргизүү параметри катары кабыл алынат . Маалыматтын бул түрү талкууланат.

Стринг символдордун ырааттуулугу катары

Чынында, англис тorнен которулган String - бул сап. Туура, String түрү текст сапты билдирет. Текст сап деген эмне? Текст сап бири-бирин ээрчип келген белгилердин кандайдыр бир иреттелген ырааттуулугу. символ болуп саналат. ырааттуулук – ырааттуулук. Демек, ооба, такыр туура, String - бул ишке ашыруу java.lang.CharSequence. Эгер сиз String классынын ичин карасаңыз, анда анын ичинде символдор массивинен башка эч нерсе жок: Анын абдан жөнөкөй келишими private final char value[]; бар :java.lang.CharSequence
Java тorндеги саптар (class java.lang.String) - 1
Бизде элементтердин санын алуу, белгилүү бир элементти алуу жана элементтердин жыйындысын алуу + toString ыкмасы бар, ал муну кайтарат) Java 8де бизге келген ыкмаларды түшүнүү кызыктуураак жана бул : chars()жана codePoints() Oracle окуу куралынан " Примитивдик берorштердин" түрлөрүн "эске келтириңиз, бул char single 16-bit Unicode character. Башкача айтканда, char 0дөн 65535ке чейинки сандарды билдирген intтин жарым өлчөмүндөгү гана түрү (32 бит) (ондук маанилерди караңыз). ASCII tableсында ) . Башкача айтканда, эгер кааласак, charды int катары көрсөтө алабыз. Жана Java 8 муну колдонду. Java 8-versionсынан баштап, бизде IntStream бар - примитивдүү инттер менен иштөө үчүн агым. Ошондуктан, charSequence ичинде символдорду же code пункттарын билдирген IntStreamди алууга болот. Аларга өтүүдөн мурун, биз бул ыкманын ыңгайлуулугун көрсөтүү үчүн бир мисал көрөбүз. Келгиле, Tutorialspoint онлайн java компиляторун колдонуп , codeду аткаралы:
public static void main(String []args){
        String line = "aaabccdddc";
        System.out.println( line.chars().distinct().count() );
}
Эми ушул жөнөкөй жол менен бир катар уникалдуу символдорду ала аласыз.

CodePoints

Ошентип, биз символдор жөнүндө көрдүк. Эми булар кандай code пункттары экени белгисиз. CodePoint түшүнүгү Java пайда болгондо символду codeдоо үчүн 16 бит (жарым инт) жетиштүү болгондуктан пайда болгон. Демек, javaдагы char UTF-16 форматында берилген («Юниcode 88» спецификациясы). Кийинчерээк Юниcode 2.0 пайда болду, анын концепциясы персонажды суррогат жуп (2 символ) катары көрсөтүү болгон. Бул бизге мүмкүн болгон маанилердин диапазонун int маанисине чейин кеңейтүүгө мүмкүндүк берди. Көбүрөөк маалымат алуу үчүн, stackoverflow караңыз: " Символду code чекити менен салыштырып жатасызбы? " UTF-16 символдор үчүн JavaDoc программасында да айтылган . Ал жерде, 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). Муну стандарттуу алфавиттерде кайра чыгаруу абдан кыйын (жана балким мүмкүн эмес). Бирок белгилер тамгалар жана сандар менен бүтпөйт. Японияда алар эмодзи катары codeдоо өтө татаал нерсени ойлоп табышты - идеограммалардын жана эмотикондордун тor. Бул тууралуу Википедияда кызыктуу макала бар: “ Эмодзи ”. Келгиле, эмодзилердин мисалын табалы, мисалы: “ Эмодзи Ghost ”. Көрүнүп тургандай, ошол эле codePoint ал жерде да көрсөтүлгөн (маани = U+1F47B). Ал он алтылык форматта көрсөтүлгөн. Эгерде биз ондук санга айландырсак, биз 128123 алабыз. Бул 16 биттен ашык уруксат берет (б.а. 65535тен ашык). Аны көчүрүп алалы:
Java тorндеги саптар (class 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 белгиге туура келет. Бул сыйкыр.

Каарман

Жогоруда көргөнүбүздөй, 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()(мисалы, кашаалар. '(' күзгү сүрөтү бар ')').

String Pool

Java тorндеги саптар өзгөрүлгүс, башкача айтканда, туруктуу. Бул java.lang.String классынын JavaDoc программасында да көрсөтүлгөн . Экинчиден, ошондой эле абдан маанилүү, саптар литералдар катары көрсөтүлүшү мүмкүн:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
Башкача айтканда, ар кандай цитаталанган сап, жогоруда айтылгандай, иш жүзүндө an object болуп саналат. Жана бул суроо туулат - эгерде биз саптарды көп колдонсок жана алар көп учурда бирдей болушу мүмкүн (мисалы, "Ката" же "Ийгorктүү" тексти), саптар ар дайым түзүлбөй турганын текшерүүнүн кандайдыр бир жолу барбы? Айтмакчы, бизде дагы эле Карталар бар, анда ачкыч сап болушу мүмкүн. Анда биз, албетте, бир эле саптар ар кандай an objectтерге ээ боло албайбыз, антпесе биз Картадан an objectти ала албайбыз. Java иштеп чыгуучулары ойлонуп, ойлонуп, String Pool ойлоп табышты. Бул саптар сакталган жер, аны сап кэш деп атасаңыз болот. Бардык саптардын өзү бүтпөйт, бирок codeдо литерал менен көрсөтүлгөн саптар гана. Сиз бассейнге сызыкты өзүңүз кошо аласыз, бирок бул жөнүндө кийинчерээк. Ошентип, эсибизде бул кэш бир жерде бар. Адилет суроо: бул бассейн кайда жайгашкан? Буга жоопту stackoverflow аркылуу тапса болот: “ Javaнын String туруктуу бассейни кайда жашайт, үймөк же стек? " Ал үймөк эсинде, атайын иштөө убактысынын туруктуу бассейн аймагында жайгашкан. Runtime туруктуу бассейни класс же интерфейс виртуалдык машина тарабынан метод аймагынан түзүлгөндө бөлүнөт - үймөктүн атайын аймагы, ага Java Virtual Machine ичиндеги бардык жиптер кире алат. String pool бизге эмне берет? Бул бир нече артыкчылыктарга ээ:
  • Бир эле түрдөгү an objectтер түзүлбөйт
  • Шилтеме боюнча салыштыруу теңдөөлөр аркылуу символдор боюнча салыштырууга караганда тезирээк
Бирок биз түзүлгөн an objectти ушул кэшке салгыбыз келсе эмне болот? Андан кийин, бизде атайын ыкма бар: 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 жасай турганыбызды эске алыңыз. Башкача айтканда, интерн бизге кэштен String кайтарып берет, бирок биз кэштен издеген түпнуска Стринг тазалоо үчүн ыргытылат, анткени ал жөнүндө башка эч ким билбейт. Бул, албетте, ресурстарды ашыкча керектөө =( Ошондуктан, мүмкүн болушунча күтүлбөгөн жана аныктоо кыйын каталарды болтурбоо үчүн, ар дайым бирдейликти колдонуу менен саптарды салыштыруу керек.
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test.equals(test2));
}
Equals символ боюнча сапты салыштырууну аткарат.

Конкатенация

Биз эстегендей, саптарды кошууга болот. Жана биз эстегендей, биздин кылдар өзгөрүлгүс. Анда ал кантип иштейт? Туура, жаңы линия түзүлөт, ал кошулуп жаткан an objectтердин символдорунан турат. Плюс конкатенациянын миллиондогон versionлары бар. Кээ бирөөлөр ар бир жолу жаңы an object болот деп ойлошсо, башкалары дагы бир нерсе болот деп ойлошот. Бирок бир гана адам туура болушу мүмкүн. Жана кимдир бирөө 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 тorндеги саптар (class java.lang.String) - 3
Албетте, циклде, StringBuilder аркылуу бириктирүүнү өзүңүз жасаганыңыз жакшы. Жана кандайдыр бир сыйкырдан улам эмес, StringBuilder циклден мурун түзүлүп, циклдин өзүндө гана тиркеме пайда болот. Айтмакчы, бул жерде дагы бир кызык нерсе бар. Мыкты макала бар: “ Java'да саптарды иштетүү. I бөлүк: String, StringBuffer, StringBuilder ." Комментарийлерде көптөгөн пайдалуу маалыматтар. Мисалы, көрүнүштү бириктиргенде, new StringBuilder().append()...toString()демейки боюнча иштетилген -XX:+OptimizeStringConcat опциясы менен жөнгө салынган ички оптималдаштыруу күчүндө экени көрсөтүлгөн. intrinsic - "ички" деп которулган. JVM мындай нерселерди өзгөчө жол менен иштетет, аларды Native катары иштетет, JNI кошумча чыгымдарысыз гана. Кененирээк: " HotSpot VMдеги ички методдор ".

StringBuilder жана StringBuffer

Биз жогоруда көргөндөй, StringBuilder абдан пайдалуу курал болуп саналат. Саптар өзгөрүлгүс, б.а. өзгөрүлгүс. А мен аны бүктөйүн деп жатам. Ошондуктан, бизге жардам берүү үчүн 2 класс берилет: StringBuilder жана StringBuffer. Экөөнүн ортосундагы негизги айырма StringBuffer JDK1.0-де киргизилген, ал эми StringBuilder керексиз ыкманы синхрондоштуруунун көбөйгөн чыгымдарын жок кылуу үчүн StringBufferдин синхрондолбогон versionсы катары java 1.5те келген. Бул класстардын экөө тең абстракттуу класстын AbstractStringBuilder ишке ашырылышы - символдордун өзгөрүлмө ырааттуулугу. Шармдардын массивинин ичинде сакталган, ал эрежеге ылайык кеңейтилген: value.length * 2 + 2. Демейки боюнча, StringBuilderдин өлчөмү (кубаттуулугу) 16.

Салыштыруу

саптар салыштырууга болот, б.а. салыштыруу ыкмасын ишке ашыруу. Бул каармандарды салыштыруу аркылуу ишке ашырылат. Кызыктуусу, минималдуу узундук эки саптан тандалып, анын үстүнөн цикл аткарылат. Ошондуктан, compareTo биринчи дал келбеген символдордун int маанилеринин ортосундагы айырманы эң кичине сап узундугуна чейин кайтарат же бардык символдор саптын минималдуу узундугуна дал келсе, сап узундуктарынын ортосундагы айырманы кайтарат. Бул салыштыруу "лексикографиялык" деп аталат.

Java Strings менен иштөө

String көптөгөн пайдалуу ыкмалары бар:
Java тorндеги саптар (class java.lang.String) - 4
Сап менен иштөө үчүн көптөгөн тапшырмалар бар. Мисалы, Coding Bat боюнча . Ошондой эле курстар боюнча курс бар: " Саптардагы алгоритмдер ".

Корутунду

Бул класстын кыскача баяндамасы да абдан чоң орун ээлейт. Бул баары эмес. Мен JPoint 2015 репортажын көрүүнү сунуштайм: Алексей Шипилев - Catechism java.lang.String
#Вячеслав
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION