Работа со строками в java. строки как объекты. классы string, stringbuffer и stringbuilder

      Комментарии к записи Работа со строками в java. строки как объекты. классы string, stringbuffer и stringbuilder отключены

Класс String инкапсулирует действия со строками. Объект типа String – строка, состоящая из произвольного числа символов, от 0 до 2*109. Литерные константы типа String представляют собой последовательности символов, заключённые в двойные кавычки:

”A”, ”abcd”, ”abcd”, ”Мама моет раму”, ” ”.

Это так называемые “длинные” строки. Внутри литерной строковой константы не разрешается использовать ряд символов — вместо них применяются управляющие последовательности.

Внутри строки разрешается использовать переносы на новую строку. Но литерные константы с такими переносами запрещены, и надо ставить управляющую последовательность “\n”. К сожалению, такой перенос строки не срабатывает в компонентах.

Разрешены пустые строки, не содержащие ни одного символа.

В языке Java строковый и символьный тип несовместимы. Поэтому ”A” – строка из одного символа, а ‘A’ – число с ASCII кодом символа ”A”. Это заметно усложняет работу со строками и символами.

Строки можно складывать: если s1 и s2 строковые литерные константы или переменные, то результатом операции s1+s2 будет строка, являющаяся сцеплением (конкатенацией) строк, хранящихся в s1 и s2. Например, в результате операции

String s=”Это ”+”моя строка”;

в переменной s будет храниться строковое значение ”Это моя строка”.

Для строк разрешён оператор ”+=”. Для строковых операндов s1 и s2 выражение

s1+=s2 эквивалентно выражению s1=s1+s2.

Любая строка (набор символов) является объектом – экземпляром класса String. Переменные типа String являются ссылками на объекты, что следует учитывать при передаче параметров строкового типа в подпрограммы, а также при многократных изменениях строк. При каждом изменении строки в динамической области памяти создаётся новый объект, а прежний превращается в “мусор”. Поэтому при многократных изменениях строк в цикле возникает много мусора, что нежелательно.

Очень частой ошибкой является попытка сравнения строк с помощью оператора “==”. Например, результатом выполнения следующего фрагмента

String s1=Строка типа String;

String s2=Строка;

s2+= типа String;

if(s1==s2)

System.out.println(s1 равно s2);

else

System.out.println(s1 не равно s2);

будет вывод в консольное окно строки “s1 не равно s2”, так как объекты-строки имеют в памяти разные адреса. Сравнение по содержанию для строк выполняет оператор equals. Поэтому если бы вместо s1==s2 мы написали s1.equals(s2), то получили бы ответ “s1 равно s2”.

Удивительным может показаться факт, что результатом выполнения следующего фрагмента

String s1=Строка;

String s2=Строка;

if(s1==s2)

System.out.println(s1 равно s2);

else

System.out.println(s1 не равно s2);

будет вывод в консольное окно строки “s1 равно s2”. Дело в том, что оптимизирующий компилятор Java анализирует имеющиеся в коде программы литерные константы, и для одинаковых по содержанию констант использует одни и те же объекты-строки.

В остальных случаях то, что строковые переменные ссылочные, обычно никак не влияет на работу со строковыми переменными, и с ними можно действовать так, как если бы они содержали сами строки.

В классе String имеется ряд методов. Перечислим важнейшие из них. Пусть s1 и subS имеют тип String, charArray – массив символов char[], ch1 – переменная или значение типа char, а i, index1 и count (“счёт, количество”) – целочисленные переменные или значения. Тогда

String.valueOf(параметр) – возвращает строку типа String, являющуюся результатом преобразования параметра в строку. Параметр может быть любого примитивного или объектного типа.

String.valueOf(charArray, index1,count) – функция, аналогичная предыдущей для массива символов, но преобразуется count символов начиная с символа, имеющего индекс index1.

У объектов типа String также имеется ряд методов. Перечислим важнейшие из них.

s1.charAt(i) – символ в строке s1, имеющий индекс i (индексация начинается с нуля).

s1.endsWith(subS) – возвращает true в случае, когда строка s1 заканчивается последовательностью символов, содержащихся в строке subS.

s1.equals(subS) — возвращает true в случае, когда последовательностью символов, содержащихся в строке s1, совпадает с последовательностью символов, содержащихся в строке subS.

s1.equalsIgnoreCase(subS) – то же, но при сравнении строк игнорируются различия в регистре символов (строчные и заглавные буквы не различаются).

s1.getBytes() – возвращает массив типа byte[], полученный в результате платформо-зависимого преобразования символов строки в последовательность байт.

s1.getBytes(charset) – то же, но с указанием кодировки (charset). В качестве строки charset могут быть использованы значения “ISO-8859-1” (стандартный латинский алфавит в 8-битовой кодировке), “UTF-8”, “UTF-16” (символы UNICODE) и другие.

s1.indexOf(subS) – индекс позиции, где в строке s1 первый раз встретилась последовательность символов subS.

s1.indexOf(subS,i) – индекс позиции начиная с i, где в строке s1 первый раз встретилась последовательность символов subS.

s1. lastIndexOf (subS) – индекс позиции, где в строке s1 последний раз встретилась последовательность символов subS.

s1. lastIndexOf (subS,i) – индекс позиции начиная с i, где в строке s1 последний раз встретилась последовательность символов subS.

s1.length() – длина строки (число 16-битных символов UNICODE, содержащихся в строке). Длина пустой строки равна нулю.

s1.replaceFirst(oldSubS,newSubS) – возвращает строку на основе строки s1, в которой произведена замена первого вхождения символов строки oldSubS на символы строки newSubS.

s1.replaceAll(oldSubS,newSubS)– возвращает строку на основе строки s1, в которой произведена замена всех вхождений символов строки oldSubS на символы строки newSubS.

s1.split(separator) – возвращает массив строк String[], полученный разделением строки s1 на независимые строки по местам вхождения сепаратора, задаваемого строкой separator. При этом символы, содержащиеся в строке separator, в получившиеся строки не входят. Пустые строки из конца получившегося массива удаляются.

s1.split(separator, i) – то же, но положительное i задаёт максимальное допустимое число элементов массива. В этом случае последним элементом массива становится окончание строки s1, которое не было расщеплено на строки, вместе с входящими в это окончание символами сепараторов. При i равном 0 ограничений нет, но пустые строки из конца получившегося массива удаляются. При i

s1.startsWith(subS) – возвращает true в случае, когда строка s1 начинается с символов строки subs.

s1.startsWith(subs, index1) – возвращает true в случае, когда символы строки s1 с позиции index1 начинаются с символов строки subs.

s1.substring(index1) – возвращает строку с символами, скопированными из строки s1 начиная с позиции index1.

s1.substring(index1,index2) – возвращает строку с символами, скопированными из строки s1 начиная с позиции index1 и кончая позицией index2.

s1.toCharArray() – возвращает массив символов, скопированных из строки s1.

s1.toLowerCase() – возвращает строку с символами, скопированными из строки s1, и преобразованными к нижнему регистру (строчным буквам). Имеется вариант метода, делающего такое преобразование с учётом конкретной кодировки (locale).

s1.toUpperCase() — возвращает строку с символами, скопированными из строки s1, и преобразованными к верхнему регистру (заглавным буквам). Имеется вариант метода, делающего такое преобразование с учётом конкретной кодировки (locale).

s1.trim() – возвращает копию строки s1, из которой убраны ведущие и завершающие пробелы.

В классе Object имеется метод toString(), обеспечивающий строковое представление объекта. Конечно, оно не может отражать все особенности объекта, а является представлением “по мере возможностей”. В самом классе Object оно обеспечивает возврат методом полного имени класса (квалифицированное именем пакета), затем идёт символ “@”, после которого следует число – хэш-код объекта (число, однозначно характеризующее данный объект во время сеанса работы) в шестнадцатеричном представлении. Поэтому во всех классах-наследниках, где этот метод не переопределён, он возвращает такую же конструкцию. Во многих стандартных классах этот метод переопределён. Например, для числовых классов метод toString() обеспечивает вывод строкового представления соответствующего числового значения. Для строковых объектов — возвращает саму строку, а для символьных (тип Char) — символ.

При использовании операций “+” и “+=” с операндами, один из которых является строковым, а другой нет, метод toString() вызывается автоматически для нестрокового операнда. В результате получается сложение (конкатенация) двух строк. При таких действиях следует быть очень внимательными, так как результат сложения более чем двух слагаемых может оказаться сильно отличающимся от ожидаемого. Например,

String s=1+2+3;

даст вполне ожидаемое значение s==”6”. А вот присваивание

String s=”Сумма =”+1+2+3;

даст не очень понятное начинающим программистам значение ” Сумма =123”. Дело в том, что в первом случае сначала выполняются арифметические сложения, а затем результат преобразуется в строку и присваивается левой части. А во втором сначала производится сложение ”Сумма =”+1. Первый операнд строковый, а второй – числовой. Поэтому для второго операнда вызывается метод toString(), и складываются две строки. Результатом будет строка ”Сумма =1”. Затем складывается строка ”Сумма =1” и число 2. Опять для второго операнда вызывается метод toString(), и складываются две строки. Результатом будет строка ”Сумма =12”. Совершенно так же выполняется сложение строки ”Сумма =12” и числа 3.

Ещё более странный результат получится при присваивании

String s=1+2+” не равно ”+1+2;

Следуя изложенной выше логике мы получаем, что результатом будет строка

“3 не равно 12”.

Выше были приведены простейшие примеры, и для них всё достаточно очевидно. Если же в такого рода выражениях используются числовые и строковые функции, да ещё с оператором “ ? : ”, результат может оказаться совершенно непредсказуемым.

Кроме указанных выше имеется ряд строковых операторов, заданных в оболочечных числовых классах. Например, мы уже хорошо знаем методы преобразования строковых представлений чисел в числовые значения

Byte.parseByte(строка)

Short.parseShort(строка)

Integer.parseInt(строка)

Long.parseLong(строка)

Float.parseFloat(строка)

Double.parseDouble(строка)

и метод valueOf(строка), преобразующий строковые представления чисел в числовые объекты – экземпляры оболочечных классов Byte, Short, Character, Integer, Long, Float, Double. Например,

Byte.valueOf(строка) , и т.п.

Кроме того, имеются методы классов Integer и Long для преобразования чисел в двоичное и шестнадцатеричное строковое представление:

Integer.toBinaryString(число)

Integer.toHexString(число)

Long.toBinaryString(число)

Long.toHexString(число)

Имеется возможность обратного преобразования – из строки в объект соответствующего класса (Byte, Short, Integer, Long) с помощью метода decode:

Byte.decode(строка) , и т.п.

Также полезны методы для анализа отдельных символов:

Character.isDigit(символ) – булевская функция, проверяющая, является ли символ цифрой.

Character.isLetter(символ) – булевская функция, проверяющая, является ли символ буквой.

Character.isLetterOrDigit(символ) – булевская функция, проверяющая, является ли символ буквой или цифрой.

Character.isLowerCase(символ) – булевская функция, проверяющая, является ли символ символом в нижнем регистре.

Character.isUpperCase(символ) – булевская функция, проверяющая, является ли символ символом в верхнем регистре.

Character.isWhitespace(символ) – булевская функция, проверяющая, является ли символ “пробелом в широком смысле” – пробелом, символом табуляции, перехода на новую строку и т.д.

Для того чтобы сделать работу с многочисленными присваиваниями более эффективной, используются классы StringBuffer и StringBuilder. Они особенно удобны в тех случаях, когда требуется проводить изменения внутри одной и той же строки (убирать или вставлять символы, менять их местами, заменять одни на другие). Изменение значений переменных этого класса не приводит к созданию мусора, но несколько медленнее, чем при работе с переменными типа String. Класс StringBuffer рекомендуется использовать в тех случаях, когда используются потоки (threads) – он, в отличие от классов String и StringBuilder, обеспечивает синхронизацию строк. Класс StringBuilder, введённый начиная с JDK 1.5, полностью ему подобен, но синхронизации не поддерживает. Зато обеспечивает большую скорость работы со строками (что обычно бывает важно только в лексических анализаторах).

К сожалению, совместимости по присваиванию между переменными этих классов нет, как нет и возможности преобразования этих типов. Но в классах StringBuffer и StringBuilder имеется метод sb.append(s), позволяющий добавлять в конец “буферизуемой” строки sb обычную строку s. Также имеется метод sb.insert(index,s), позволяющий вставлять начиная с места символа, имеющего индекс index, строку s.

Пример:

StringBuffer sb=new StringBuffer();

sb.append(типа StringBuffer);

sb.insert(0,Строка );

System.out.println(sb);

Кроме строк в методы append и insert можно подставлять

Буферизуемые и обычные строки можно сравнивать на совпадение содержания:

s1.contentEquals(sb) – булевская функция, возвращающая true в случае, когда строка s1 содержит такую же последовательность символов, как и строка sb.

Работа с графикой

Вывод графики осуществляется с помощью объектов типа java.awt.Graphics. Для них определён ряд методов, описанных в следующей далее таблице.

Подразумевается, что w- ширина области или фигуры, h- высота; x,y- координаты левого верхнего угла области. Для фигуры x,y- координаты левого верхнего угла прямоугольника, в который вписана фигура.

Параметры вывода графики
Color getColor() Узнать текущий цвет рисования.
setColor(Color c) Задать текущий цвет рисования.
Font getFont() Узнать текущий фонт для вывода текстовой информации.
setFont(Font f) Установить текущий фонт для вывода текстовой информации. Экземпляр фонта создаётся с помощью конструктора Font(“имяФонта”,стильФонта,размерФонта)
FontMetrics getFontMetrics() Узнать параметры текущего фонта
FontMetrics getFontMetrics(Font f) Узнать параметры для произвольного фонта f
setXORMode(Color c1) Установка режима рисования XOR (“исключающее или”) для цвета c1. При этом вывод точки цвета color даёт цвет, равный побитовому значению color ^ c1 (то есть color XOR c1) для числовой RGB-кодировки цвета. Повторный вывод графического изображения на то же место приводит к восстановлению первоначального изображения в области вывода.
setPaintMode() Возврат в обычный режим из режима рисования XOR.
translate(x0,y0) Сдвиг начала координат графического контекста в точку x0,y0. Все координаты, указанные при выводе графических примитивов, отсчитываются относительно этого начала координат.
Рисование контурных фигур
drawLine(x1,y1,x2,y2) Вывод линии из точки с координатами x1,y1 в точку x2,y2
drawRect(x,y,w,h) Вывод прямоугольника.
drawRoundRect(x,y,w,h,arcWidth,arcHeight) Вывод скруглённого прямоугольника.
draw3DRect(x,y,w,h,isRaised) Вывод “объёмного” прямоугольника. Если переменная isRaised ==true, он “выпуклый” (raised), иначе — “вдавленный”.
drawPolygon(Polygon p);drawPolygon(int[] xPoints, int[] yPoints, int nPoints) Вывод многоугольника по массиву точек, nPoints – число точек.
drawPolyline(int[] xPoints,int[] yPoints, int nPoints) Вывод незамкнутой ломаной линии по массиву точек, nPoints – число точек.
drawOval(x,y,w,h) Вывод эллипса.
drawArc(x,y,w,h,startAngle,arcAngle) Вывод дуги эллипса. Начальный угол startAngle и угол, задающий угловой размер дуги arcAngle, задаются в градусах.
drawImage(Image img,int x,int y, ImageObserver observer) и другие перегруженные варианты метода Вывод изображения.
Рисование заполненных фигур
clearRect(x,y,w,h) Очистка прямоугольника (заполнение текущим цветом)
fillRect(x,y,w,h) Вывод прямоугольника, заполненного текущим цветом.
fillRoundRect(x,y,w,h,arcWidth,arcHeight) Вывод скруглённого прямоугольника, заполненного текущим цветом.
fill3DRect(x,y,w,h, isRaised) Вывод “объёмного” прямоугольника, заполненного текущим цветом. Если переменная isRaised ==true, он “выпуклый” (raised), иначе — “вдавленный”.
fillPolygon(Polygon p)fillPolygon(int[] xPoints, int[] yPoints, int nPoints) Вывод многоугольника, заполненного текущим цветом.
fillOval(x,y,w,h) Вывод эллипса, заполненного текущим цветом.
fillArc(x,y,w,h,startAngle,arcAngle) Вывод сектора эллипса, заполненной текущим цветом. Заполняется сектор, ограниченный отрезками из центра эллипса в концы дуги, и самой дугой.
copyArea(x,y,w,h,dx,dy) Копирование области на новое место, сдвинутое от старого на dx,dy
Вывод текстовой информации
drawString(s,x,y) Вывод строки s
drawChars(char[] data,int offset,int length,int x,int y) Вывод массива символов
drawBytes(byte[] data,int offset,int length,int x,int y) Вывод символов, представленных как последовательность байт
Управление областью вывода
setClip(x,y,w,h)setClip(Shape clip) Установка новых границ области вывода. Вне этой области при выводе графических примитивов они усекаются (не выводятся).
clipRect(x,y,w,h) Сужение области вывода.
Rectangle getClipBounds()Rectangle getClipBounds(Rectangle r) Возвращает параметры прямоугольника, в который вписана область вывода.
Graphics create() g1=g.create()- создание копии графического объекта g
dispose() Деструктор — уничтожение графического объекта с одновременным высвобождением ресурсов (без ожидания, когда это сделает сборщик мусора).

Пример метода, работающего с графикой.

java.awt.Graphics g,g1;

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

java.awt.Graphics g,g1;

g=jPanel1.getGraphics();

int x1=20,x2=120,y1=20,y2=120;

int x3=20,y3=20,w3=60,h3=80;

int x4=30,y4=60,w4=30,h4=40;

int x0=10,y0=10,w0=10,h0=10;

int w1=80,h1=120;

g.setClip(0,0,60,80);//границы области вывода

g.drawLine(x1,y1,x2,y2);//линия

g.drawOval(x3,y3,w3,h3);//эллипс

g.clipRect(x4,y4,20,20);//сужение области вывода

g.clearRect(x4,y4,w4,h4);//очистка прямоугольника

g.setClip(0,0,200,280); //новые границы области вывода

g.copyArea(x1,y1,w1,h1,60,0);

g.draw3DRect(10,20,w1,h1,false);

g.drawPolygon(new java.awt.Polygon(new int[]{10,10,20,40},

new int[]{10,20,30,60},4) );

}

В случае попытки такого использования возникает проблема: при перерисовке графического контекста всё выведенное изображение исчезает. А перерисовка вызывается автоматически при изменении размера окна приложения, а также его восстановлении после минимизации или перекрытия другим окном.

Для того, чтобы результаты вывода не пропадали, в классе приложения требуется переопределить метод paint, вызываемый при отрисовке. Код этого метода может выглядеть так:

public void paint(java.awt.Graphics g){

super.paint(g);

g=jPanel1.getGraphics();

… – команды графического вывода

}

Правда, при изменении размера окна приложения этот код не сработает, и для панели надо будет назначить обработчик

private void jPanel1ComponentResized (java.awt.event.ComponentEvent evt) {

… – команды графического вывода

}

То, что для изменения размера компонента следует писать отдельный обработчик, вполне разумно – ведь при восстановлении окна требуется только воссоздать изображение прежнего размера. А при изменении размера может потребоваться масштабирование выводимых элементов. Поэтому алгоритмы вывода графики в этих случаях заметно отличаются.

В случае отрисовки из обработчика какого-либо события изменения графического контекста не происходит до окончания обработчика. Это принципиальная особенность работы по идеологии обработчиков событий – пока не кончится один обработчик, следующий не начинается. Для досрочной отрисовки непосредственно во время выполнения обработчика события служит вызов метода update(Graphics g). Пример:

for(int i=0;i

FiguresUtil.moveFigureBy(figure,dx,dy);

update(g);

};

При работе со статическими изображениями изложенных алгоритмов вполне достаточно. Однако при использовании движущихся элементов во многих графических системах возникает мельтешение, связанное с постоянными перерисовками. В этих случаях обычно применяют идеологию двойной буферизации: отрисовку элементов по невидимому буферному изображению, а затем показ этого изображения в качестве видимого. А то изображение, которое было видимо, при этом становится невидимым буфером.

Исключительные ситуации

Статьи к прочтению:

Java SE. Урок 26. Класс String и его методы


Похожие статьи:

  • Функции работы со строками

    Символы и строки. Символы Символ – это один знак. Любой – буква, цифра, арифметический знак или пробел, знак препинания или подчеркивания… А также…

  • Работа с файлами и папками

    Концепция работы с файлами в Java включает две составляющие: Работа с файлами и папками с помощью объектов типа File. Обеспечивает работу с именами…