Java где хранятся string

Строки в Java (class java.lang.String)

Java-университет

Путь программиста – сложный и долгий процесс. И в большинстве случаев начинается он с программы, которая выводит Hello World на экран. Java не исключение (см. Lesson: The «Hello World!» Application). Как мы видим, вывод сообщения осуществляется при помощи System.out.println(«Hello World!»); Если посмотреть в Java API, то метод System.out.println принимает входным параметром String. Про этот тип данных и пойдёт речь.

String как последовательность символов

Собственно, String в переводе с английского – строка. Так и есть, тип String представляет текстовую строку. А чем же является текстовая строка? Текстовая строка — это какая-то упорядоченная последовательность символов, которые идут друг за другом. Символ – char. Последовательность – sequence. Так что да, абсолютно правильно, String является реализацией java.lang.CharSequence . А если заглянуть внутрь самого класса String, то внутри него ничто иное как массив char’ов: private final char value[]; У java.lang.CharSequence довольно простой контракт:

Строки в Java (class java.lang.String) - 1

У нас есть метод получения количества элементов, получения конкретного элемента и получения набора элементов + непосредственно сам метод toString, который вернёт this) Интереснее разобраться в методах, которые пришли к нам в Java 8, а это: chars() и codePoints() Вспоминаем по Tutorial от Oracle «Primitive Data Types», что char — это single 16-bit Unicode character .То есть по сути char это просто тип размером в половину типа int (32 бита), который представляет числа от 0 до 65535 (см. decimal значения в ASCII Table). То есть при желании мы можем char представить в виде int. И в Java 8 этим воспользовались. Начиная с 8 версии Java у нас появляется IntStream — стрим для работы с примитивными int’ами. Поэтому в charSequence есть возможность получить IntStream, представляющий или char’ы или codePoint’ы. Прежде чем перейдём к ним, увидим пример, чтобы показать всё удобство этого подхода. Воспользуемся Tutorialspoint online java compiler’ом и выполним код:

 public static void main(String []args)

CodePoints

Итак, про chars мы увидели. Теперь непонятно, что за code points такие. Понятие codePoint появилось потому, что когда Java появилась, то хватало 16 бит (половина int) чтобы закодировть символ. Поэтому char в java представлен в UTF-16 формате («Unicode 88» specification). Позже повяился Unicode 2.0, концепция которого заключалась в представлении символа в виде сурогатной пары (2 чаров). Это позволило расширить диапазон возможных значений до значения int. Подробнее см. на stackoverflow: «Comparing a char to a code-point?». Про UTF-16 так же указано и в JavaDoc к 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). На стандартных алфавитах довольно трудно (а может даже нельзя) воспроизвести это. Но символы буквами и цифрами не заканчиваются. В японии придумали такую сложную для кодировок штуку, как emoji — язык идеограмм и смайликов. Есть про это интересная статья на википедии: «Эмодзи». Найдём пример emoji, например такой: «Emoji Ghost». Как мы видим, там даже указан тот самый codePoint (значение = U+1F47B). Указан он в шестнадцатеричном формате. Если перевести в десятичное число, то получим 128123. Это больше, чем позволяет 16 бит (т.е. больше чем 65535). Скопируем его:

Читайте также:  Example Web Page

Строки в Java (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 >

Character

Как мы увидели выше, String’и в Java состоят из char. Примитивный тип позволяет хранить значение, а вот обёртка 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 неизменяемы, то есть константны. В том числе об этом указано в самом JavaDoc класса java.lang.String. Второе и тоже очень важное – строки могут задаваться литералами:

 String literalString = "Hello, World!"; String literalString = "Hello, World!"; 
  • Не будут создаваться однотипные объекты
  • Сравнение по ссылке быстрее, чем посимвольное сравнение через equals
 public static void main(String[] args)

Как видите, строки одинаковые, но результат будет false. А всё потому, что == сравнивает не по значению, а по ссылке. А вот так работает:

 public static void main(String[] args)

Только заметим, что new String всё равно мы сделаем. То есть intern нам вернёт String из кэша, а вот изначальный String, по которому мы искали в кэше, будет выброшен на очистку, т.к. никто больше про него не знает. На лицо лишнее потребление ресурсов =( Поэтому, сравнивать строки нужно всегда через equals, чтобы уйти по возможности от внезапных и трудно определяемых ошибок.

 public static void main(String[] args)

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

Как мы помним, строки можно складывать. И как мы помним строки у нас неизменяемы. Так как же тогда это работает? Всё верно, создаётся новая строка, которая состоит из символов складываемых объектов. Существует миллион версий о том, как работает конкатенация через плюс. Кто-то считает что будет каждый раз новый объект, кто-то считает что будет ещё что-то. Но прав может быть кто-то один. И этот кто-то – компилятор javac. Воспользуемся сервисом онлайн компилятора и выполним:

Теперь сохраним это как zip архив, извлечём в каталог и выполним: javap –c HelloWorld И тут мы всё узнаем:

Строки в Java (class java.lang.String) - 3

В цикле, конечно, лучше делать конкатенацию через StringBuilder самим. И не потому что какая-то магия, а чтобы StringBuilder создавался до цикла, а в самом цикле происходил только append. Кстати, тут есть ещё одна интересность. Есть отличная статья: «Обработка строк в Java. Часть I: String, StringBuffer, StringBuilder». Много полезного в комментариях. Например, указано, что при конкатенации вида new StringBuilder().append(). toString() действует intrinsic оптимизация, регулируемая опцией -XX:+OptimizeStringConcat, которая по умолчанию включена. intrinsic — переводится как «внутренний». Такие вещи JVM обрабатывает особенным образом, обрабатывая их как Native, только без дополнительных затрат на JNI. Подробнее: «Intrinsic Methods in HotSpot VM».

StringBuilder и StringBuffer

Как мы выше видели, StringBuilder очень полезный инструмент. Строки являются immutable, т.е. неизменяемыми. А складывать хочется. Поэтому, нам в помощь даны 2 класса: StringBuilder и StringBuffer. Основное отличие между ними в том, что StringBuffer появился в JDK1.0, в то время как StringBuilder пришёл в java 1.5 как не синхронизированная версия StringBuffer, чтобы снять повышенные затраты на ненужную синхронизацию методов. Оба эти классы являются реализацией абстрактного класса AbstractStringBuilder — A mutable sequence of characters. Внутри хранится массив чаров, который расширяется по правилу: value.length * 2 + 2. По умолчанию размер (capacity) у StringBuilder’а равен 16.

Comparable

Строки являются comparable, т.е. реализуют метод compareTo. Выполняется это при помощи посимвольного сравнения. Интересно, что из двух строк выбирается минимальная длинна и по ней выполняется цикл. Поэтому, compareTo вернёт или разницу между int значениями первых несовпавших символов в пределе наименьшей из длинн строк, либо вернёт разницу между длиннами строк, если в пределах минимальной длинны строки все символы совпадают. Такое сравнение называется «лексикографическим».

Работа со строками Java

Строки в Java (class java.lang.String) - 4

На работу со строками сущесвует множество задач. Например, на Coding Bat. Так же есть курс на coursera: «Algorithms on Strings».

Заключение

Даже небольшой обзор данного класса занимает внушительное место. А это ещё не всё. Настоятельно рекомендую к просмотру доклад с JPoint 2015 года: Алексей Шипилёв — Катехизис java.lang.String

Источник

Оцените статью