Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Тема 2.20 Аргументы переменной длины
В JDK 5 была добавлена новая функциональная возможность, которая упрощает создание методов, принимающих переменное количество аргументов. Эта функциональная возможность получила название varargs (сокращение термина variable-length arguments – аргументы переменной длины). Метод, который принимает переменное число аргументов, называют методом переменной арности, или просто методом varargs. Ситуации, в которых методу нужно передавать переменное количество аргументов, встречаются не так уж редко. Например, метод, который открывает подключение к Internet, может принимать имя пользователя, пароль, имя файла, протокол и тому подобное, но применять значения, заданные по умолчанию, если какие-либо из этих сведений опущены. В этой ситуации было бы удобно передавать только те аргументы, для которых заданные по умолчанию значения не применимы. Еще один пример – метод printf (), входящий в состав библиотеки ввода-вывода Java. До появления версии J2SE 5 обработка аргументов переменной длины могла выполняться двумя способами, ни один из которых не был особенно удобным. Во-первых, если максимальное количество аргументов было небольшим и известным, можно было создавать перегруженные версии метода – по одной для каждого возможного способа вызова метода. Хотя этот способ подходит для ряда случаев, он применим только к узкому классу ситуаций. В тех случаях, когда максимальное число возможных аргументов было большим или неизвестным, применялся второй подход, при котором аргументы помещались в массив, а затем массив передавался методу. Листинг 2.23иллюстрирует этот подход. Листинг 2.23 // Использование массива для передачи методу переменного // количества аргументов. Это старый стиль подхода // к обработке аргументов переменной длины. public class PassArray { public static void vaTest(int v[]) { System.out.print(" Количествоаргументов: " + v.length + " Содержимое: " ); for (int x: v) { System.out.print(x + " " ); } System.out.println(); }
public static void main(String args[]) { // Обратите внимание на способ создания массива // для хранения аргументов. int nl[] = {10}; int n2[] = {1, 2, 3}; int n3[] = {}; vaTest(nl); // 1 аргумент vaTest(n2); // 3 аргумента vaTest(n3); // безаргументов } } Эта программа создает следующий вывод: Количество аргументов: 1 В программе методу vaTest () аргументы передаются через массив v. Этот старый подход к обработке аргументов переменной длины позволяет методу vaTest () принимать любое число аргументов. Однако он требует, чтобы эти аргументы были вручную помещены в массив до вызова метода vaTest (). Создание массива при каждом вызове метода vaTest () не только трудоемкая, но и чреватая ошибками задача. Функциональная возможность использования методов varargs обеспечивает более простой и эффективный подход. Для указания аргумента переменной длины используют три точки (...). Например, вот как метод vaTest () можно записать с использованием аргумента Переменной длины: public static void vaTest(int... v) { Эта синтаксическая конструкция указывает компилятору, что метод vaTest () может вызываться с нулем или более аргументов. В результате v неявно объявляется как массив типа int []. Таким образом, внутри метода vaTest () доступ к v осуществляется с использованием синтаксиса обычного массива. Предыдущая программа с применением метода vararg приобретает следующий вид(листинг 2.24): Листинг 2.24 public class VarArgs { // теперь vaTest () использует аргументы переменной длины public static void vaTest(int... v) { System.out.print(" Количествоаргументов: " + v.length + " Содержимое: " ); for (int x: v) { System.out.print(x + " " ); } System.out.println(); } public static void main(String args[]) { // Обратите внимание на возможные способы вызова // vaTest () с переменным числом аргументов. vaTest(10); //1 аргумент vaTest(1, 2, 3); //3 аргумента vaTest(); // без аргументов } } Вывод этой программы совпадает с выводом исходной версии. Отметим две важные особенности этой программы. Во-первых, как уже было сказано, внутри метода vaTest () переменная v действует как массив. Это обусловлено тем, что v является массивом. Синтаксическая конструкция... просто указывает компилятору, что метод будет использовать переменное количество аргументов, и что эти аргументы будут храниться в массиве, на который ссылается переменная v. Во-вторых, в методе main () метод vaTest () вызывается с различным количеством аргументов, в том числе, и вовсе без аргументов. Аргументы автоматически помещаются в массив и передаются переменной v. В случае отсутствия аргументов длина массива равна нулю. Наряду с параметром переменной длины массив может содержать " нормальные" параметры. Однако параметр переменной длины должен быть последним параметром, объявленным методом. Например, следующее объявление метода вполне допустимо: intdolt(inta, intb, doubleс, int... vals) { В данном случае первые три аргумента, указанные в обращении к методу dolt (), соответствуют первым трем параметрам. Все остальные аргументы считаются принадлежащими параметру vals. Помните, что параметр vararg должен быть последним. Например, следующее объявление записано неправильно: int dolt (int a, int b, double с, int... vals, boolean stopFlag) { В этом примере предпринимается попытка объявления обычного параметра после параметра типа vararg, что недопустимо. Существует еще одно ограничение, о котором следует знать: метод должен содержать только одни параметр типа varargs. Например, следующее объявление также неверно: intdolt (inta, intb, doubleс, int... vals, double... morevals) { Попытка объявления второго параметра типа vararg недопустима. Рассмотрим измененную версию метода vaTest (), которая принимает обычный аргумент и аргумент переменной длины в листинге 2.25. Листинг 2.25 public class VarArgs { // Использование- аргумента переменой длины совместно со стандартными аргументами. //В этом примере msg – обычный параметр, av – параметр vararg. public static void vaTest(String msg, int... v) { System.out.print(msg + v.length + " Содержимое: " ); for (int x: v) { System.out.print(x + " " ); } System.out.println(); } public static void main(String args[]) { vaTest(" Одинпараметр vararg: ", 10); vaTest(" Трипараметра vararg: ", 1, 2, 3); vaTest(" Be3 параметров vararg: " ); } } Вывод это программы имеет вид: Один параметр vararg: 1 Метод, который принимает аргумент переменной длины, можно перегружать. Типы его параметра vararg могут быть различными. Именно это имеет место в вариантах vaRest (int...) и vaTest (boolean...). Помните, что конструкция... вынуждает компилятор обрабатывать параметр как массив указанного типа. Поэтому, подобно тому, как можно выполнять перегрузку методов, используя различные типы параметров массива, можно выполнять перегрузку методов vararg, используя различные типы аргументов переменной длины. В этом случае система Java использует различие в типах для определения нужного варианта перегруженного метода. Второй способ перегрузки метода vararg – добавление обычного параметра. Именно это было сделано для vaTest (String, int...). В данном случае для определения нужного метода система Java использует и количество аргументов, и их тип. Метод, поддерживающий varargs, может быть перегружен также методом, который не поддерживает эту функциональную возможность. Например, в приведенной ранее программе метод vaTest () может быть перегружен методом vaTest (int х). Эта специализированная версия вызывается только при Наличии аргумента int. В случае передаче методу двух и более аргументов int программа будет использовать varargs-версию метода vaTest (int...v). При перегрузке метода, принимающего аргумент переменной длины, могут случаться непредвиденные ошибки. Они связаны с неопределенностью, которая может возникать при вызове перегруженного метода с аргументом переменной длины. Например, рассмотрим следующую программу(листинг 2.26): Листинг 2.26 // Аргументы переменной длины, перегрузка и неопределенность. //Эта программа содержит ошибку, и ее компиляция // будетневозможна! public class VarArgs { public static void vaTest(int... v) { System.out.print(" vaTest (int...): " + " Количествоаргументов: " + v.length + " Содержимое: " ); for (int x: v) { System.out.print(x + " " ); } System.out.println(); }
public static void vaTest(boolean... v) { System.out.print(" vaTest(boolean...) " + " Количество аргументов: " + v.length + " Содержимое: " ); for (boolean x: v) { System.out.print(x + " " ); } System.out.println(); }
public static void main(String args[]) { vaTest(1, 2, 3); //OK vaTest(true, false, false); // OK vaTest(); // Ошибка: неопределенность! } } В этой программе перегрузка метода vaTest () выполняется вполне корректно. Однако ее компиляция будет невозможна из-за следующего вызова: vaTest (); // Ошибка: неопределенность! Поскольку параметр типа vararg может быть пустым, этот вызов может быть преобразован в обращение к vaTest (int...) или к vaTest (boolean...). Оба варианта допустимы. Поэтому вызов принципиально неоднозначен. Рассмотрим еще один пример неопределенности. Следующие перегруженные версии метода vaTest () изначально неоднозначны, несмотря на то, что одна из них принимает обычный параметр: static void vaTest(int... v) { } vaTest(1) Должен ли он быть преобразован в обращение к vaTest (int...) с одним аргументом переменной длины или в обращение к vaTest (int, int...) без аргументов переменной длины? Компилятор не имеет возможности ответить на этот вопрос. Таким образом ситуация неоднозначна. Из-за ошибок неопределенности, подобных описанным, в некоторых случаях придется пренебрегать перегрузкой и просто использовать два различных имени метода. Кроме того, в некоторых случаях ошибки неопределенности служат признаком концептуальных изъянов программы, которые можно устранить путем более тщательного построения решения задачи. Задание: Напишите методы с переменным числом параметров: 1). выводящий все параметры на консоль, 2). вычисляющий сумму всех параметров, 3). произведение всех параметров, 4). сортирующий параметры по возрастанию.
Тема 2.21 Строки и числа
В повседневной работе каждый программист обязательно встречается с объектами String. Объект String определяет строку символов и поддерживает операции над ней. Во многих языках программирования строка – это лишь массив символов, однако в языке Java это не так. В нем строка – это объект. Возможно, вы не догадываетесь об этом, но реально класс String уже использовался, с самого начала. Создавая строковой литерал, вы на самом деле создавали объект String. Рассмотрим приведенное ниже выражение. System.out.println(" In Java, strings are objects." ); Наличие в нем строки " In Java, strings аre objeсts." автоматически приводит к созданию объекта String. Таким образом, класс String присутствовал в предыдущих программах " за сценой". В последующих разделах мы рассмотрим, как можно использовать этот класс явным образом. Помните, что в классе String предусмотрен огромный набор методов. Здесь мы вкратце обсудим лишь некоторые из них. Большую часть возможностей класса String вам предстоит изучить самостоятельно. Объекты String создаются так же, как и объекты других типов, т.е. для этой цели используется конструктор. Например: String str = new String(" Hello" ); В данном примере создается объект String с именем str, содержащий строкусимволов " Hellо". Также есть возможность создать объект String на основе другого объекта такого же типа. Например: String str = new String(" Hello" ); String str2 = new String(str); После выполнения этих выражений объект str2 будет также содержать строку символов " Hello". Еще один способ создания объекта String показан ниже. String str = " Java strings are powerful."; В данном случае объект str инициализируется последовательностью символов " Java strings are powerful." Создав объект String, вы можете использовать его везде, где допустим строковой литерал (последовательность символов, помещенная в кавычки). Например, объект String можно передать методу println() при его вызове так, как показано в следующем листинге 2.27. Листинг 2.27 public class Main { public static void main(String args[]) { // Определение строк различными способами String str1 = new String(" Java strings are objects." ); String str2 = " They are constructed various ways."; String str3 = new String(str2); System.out.println(str1); System.out.println(str2); System.out.println(str3); } }
Класс String содержит ряд методов, предназначенных для выполнения действий над строками. Ниже описаны некоторые из них. 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.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< 0 ограничений нет, а пустые строки из конца получившегося массива не удаляются. 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, и преобразованными к нижнему регистру (строчным буквам). s1.toUpperCase()– возвращает строку с символами, скопированными из строки s1, и преобразованными к верхнему регистру (заглавным буквам). s1.trim() – возвращает копию строки s1, из которой убраны ведущие и завершающие пробелы. Листинг 2.28 public class Main { public static void main(String args[]) { Stringstr1, str2; // преобразование символа в строку str1 = String.valueOf('f'); char s[] = {'a', 'D', 'S', 'a', 'q', 'w'}; System.out.println(str1); // преобразование массива символов в строку str2 = String.valueOf(s, 0, s.length); System.out.println(str2); // вывод 5-го элемента строки System.out.println(str2.charAt(4)); //проверяет чем заканчивается строка System.out.println(str2.endsWith(" aqw" )); System.out.println(str2.toLowerCase()); //разделение строки на массив строк Stringa[] = str2.split(" a" ); for (String q: a) { System.out.println(q); } } } Кроме указанных выше имеется ряд строковых операторов, заданных в оболочечных числовых классах. Например, методы преобразования строковых представлений чисел в числовые значения 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(символ) – булевская функция, проверяющая, является ли символ “пробелом в широком смысле” – пробелом, символом табуляции, перехода на новую строку и т.д.
Использование некоторых методов демонстрирует листинг 2.29. Листинг 2.29 public class Main { public static void main(String args[]) { String str1 = " When it comes to Web programming, Java is #1."; String str2 = new String(str1); String str3 = " Java strings are powerful."; int result, idx; char ch; System.out.println(" Length of str1: " + str1.length()); // Отображение str1 поодномусимволу for (int i = 0; i < str1.length(); i++) { System.out.print(str1.charAt(i)); } System.out.println(); if (str1.equals(str2)) { System.out.println(" str1 equals str2" ); } else { System.out.println(" str1 does not equal str2" ); } if (str1.equals(str3)) { System.out.println(" str1 equals str3" ); } else { System.out.println(" str1 does not equal str3" ); } result = str1.compareTo(str3); if (result == 0) { System.out.println(" str1 and str3 are equal" ); } else if (result < 0) { System.out.println(" str1 is less than str3" ); } else { System.out.println(" str1 is greater than str3" ); } // Присвоение переменной str2 ссылки на новую строку str2 = " One Two Three One"; idx = str2.indexOf(" One" ); System.out.println(" Index of first occurence of One: " + idx); idx = str2.lastIndexOf(" One" ); System.out.println(" Index of last occurence of One: " + idx); } } Конкатенацию (объединение) двух строк обеспечивает оператор +. Например приведенная ниже последовательность выражений инициализирует переменнуюstr4 строкой " OneTwoThree". String strl = " One"; String str2 = " Two"; String str3 = " Three"; String str4 = str1 + str2 + str3; Для сравнения строк определен метод equals(). Метод equals() сравнивает последовательности символов, содержащиеся в двух объектах String, и проверяет, совпадают ли они. Так как оператор = = лишь определит, ссылаются ли две переменные на один и тот же объект. Подобно другим типам данных, строки можно объединять в массивы. В листинге 2.30 приведен пример использования массивов. Листинг 2.30 public class Main { public static void main(String args[]) { String strs[] = {" This", " is", " a", " test." }; System.out.println(" Original array: " ); for (String s: strs) { System.out.print(s + " " ); } System.out.println(" \n" ); // Внесение изменений strs[1] = " was"; strs[3] = " test, too! "; System.out.println(" Modified array: " ); for (String s: strs) { System.out.print(s + " " ); } } } Ниже приведен код программы, демонстрирующей использование метода substring() и принцип неизменности строк. Листинг 2.31 public class Main { public static void main(String args[]) { String orgstr = " Java makes the Web move."; // Формирование подстроки String substr = orgstr.substring(5, 18); System.out.println(" orgstr: " + orgstr); System.out.println(" substr: " + substr); } } Как видите, исходная строка, orgstr, остается в прежнем виде, а объект substr содержит подстроку. Перевести строковое значение в величину типа int или double можно с помощью методов parseInt() и parseDouble() классов Integer и Double. Обратное преобразование возможно при использовании метода valueOf() класса String. Кроме того, любое значение можно преобразовать в строку путем конкатенации его (+) с пустой строкой (“”). Листинг 2.32 public class Main { public static void main(String args[]) { String strInt = " 123"; String strDouble = " 123.456"; int x; double y; x = Integer.parseInt(strInt); y = Double.parseDouble(strDouble); System.out.println(" x=" + x); System.out.println(" y=" + y); strInt = String.valueOf(x + 1); strDouble = String.valueOf(y + 1); System.out.println(" strInt=" + strInt); System.out.println(" strDouble=" + strDouble);
String str; str = " num=" + 345; System.out.println(str); } } Для преобразования целого числа в десятичную, двоичную, шестнадцатеричную и восьмеричную строки используются методы toString(), toBinaryString(), toHexString() иtoOctalString(). Листинг 2.33 public class Main { public static void main(String[] args) { System.out.println(Integer.toString(262)); System.out.println(Integer.toBinaryString(262)); System.out.println(Integer.toHexString(267)); System.out.println(Integer.toOctalString(267)); } }
В листинге 2.34 приведен пример использования строк и switch. Программа определяет, образуют ли цифры данного четырехзначного числа N строговозрастающую последовательность. Листинг 2.34 public class Main { public static void main(String[] args) { String str = " "; Scanner sc = new Scanner(System.in); System.out.print(" Введите строку из 4-х символов: " ); if (sc.hasNextLine()) { str = sc.nextLine(); } if (str.length()! = 4) { System.err.println(" Строка не содержит четырех символов." ); //обработчик системной ошибки return; } for (int i = 0; i < str.length() - 1; i++) { if (str.charAt(i) > str.charAt(i + 1))//взять символ { System.out.println(" false" ); return; } } System.out.println(" true" ); } } В листинге 2.35 приведена программа, которая читает натуральное число вдесятичном представлении, а на выходе выдает это же число в десятичном представлении и на естественном языке. Например: 7 семь 204 двести четыре 52 пятьдесят два Листинг 2.35 public class Main { public static void main(String[] args) { String num = " "; char[] achNum; char curSymbol; Scanner sc = new Scanner(System.in); System.out.print(" Введите число: " ); if (sc.hasNextLine()) { num = sc.nextLine(); } StringBuffer strBuf = new StringBuffer(num); strBuf.reverse(); num = null; for (int i = strBuf.length() - 1; i > = 0; i--) { curSymbol = strBuf.charAt(i); switch (i) { case 2: // сотни printSotni(curSymbol); break; case 1: // десятки if (curSymbol! = '1') { printDeciatk(curSymbol); } else { i--; curSymbol = strBuf.charAt(i); printDeciatkWithEdinic(curSymbol); } break; case 0: //единицы printEdinic(curSymbol); break; default: System.out.println(" Такие числа программа пока не выводит." ); return; } } } // печатает названия единиц public static void printEdinic(char i) { switch (i) { case '1': System.out.print(" один " ); break; case '2': System.out.print(" два " ); break; case '3': System.out.print(" три " ); break; case '4': System.out.print(" четыре " ); break; case '5': System.out.print(" пять " ); break; case '6': System.out.print(" шесть " ); break; case '7': System.out.print(" семь " ); break; case '8': System.out.print(" восемь " ); break; case '9': System.out.print(" девять " ); break; } } // печатает названия десятков public static void printDeciatk(char i) { switch (i) { case '1': System.out.print(" десять " ); break; case '2': System.out.print(" двадцать " ); break; case '3': System.out.print(" тридцать " ); break; case '4': System.out.print(" сорок " ); break; case '5': System.out.print(" пятьдесят " ); break; case '6': System.out.print(" шестьдесят " ); break; case '7': System.out.print(" семьдесят " ); break; case '8': System.out.print(" восемьдесят " ); break; case '9': System.out.print(" девяносто " ); break; } } public static void printDeciatkWithEdinic(char i) { switch (i) { case '0': System.out.print(" десять " ); break; case '1': System.out.print(" одиннадцать " ); break; case '2': System.out.print(" двенадцать " ); break; case '3': System.out.print(" тринадцать " ); break; case '4': System.out.print(" четырнадцать " ); break; case '5': System.out.print(" пятнадцать " ); break; case '6': System.out.print(" шестнадцать " ); break; case '7': System.out.print(" семнадцать " ); break; case '8': System.out.print(" восемнадцать " ); break; case '9': System.out.print(" девятнадцать " ); break; } } // печатает сотни public static void printSotni(char i) { switch (i) { case '1': System.out.print(" сто " ); break; case '2': System.out.print(" двести " ); break; case '3': System.out.print(" триста " ); break; case '4': System.out.print(" четыреста " ); break; case '5': System.out.print(" пятьсот " ); break; case '6': System.out.print(" шестьсот " ); break; case '7': System.out.print(" семьсот " ); break; case '8': System.out.print(" восемьсот " ); break; case '9': System.out.print(" девятьсот " ); break; } } } Классы StringBuilder и StringBufferявляются “близнецами”и по своему предназначению близки к классуString, но, в отличие от последнего, содержимое и размеры объектов классовStringBuilder и StringBuffer можно изменять. Основным и единственным отличиемStringBuilder от StringBufferявляется потокобезопасность последнего. В версии 1.5.0 был добавлен непотокобезопасный (следовательно, более быстрый в обработке) класс StringBuilder, который следует применять, если не существует вероятности использования объекта в конкурирующих потоках. С помощью соответствующих методов и конструкторов объекты классовStringBuffer, StringBuilder и String можно преобразовывать друг в друга. Конструктор класса StringBuffer (также как и StringBuilder) может принимать в качестве параметра объект String или неотрицательный размер буфера. Объекты этого класса можно преобразовать в объект класса String методом toString() или с помощью конструктора класса String. Некоторые полезные методы: void setLength(int n) – установка размера буфера; void ensureCapacity(int minimum) – установка гарантированного минимального размера буфера; int capacity() – возвращение текущего размера буфера; StringBuffer append(параметры) – добавление к содержимому объекта строкового представления аргумента, который может быть символом, значением базового типа, массивом и строкой; StringBuffer insert(параметры) – вставка символа, объекта или строки в указанную позицию; StringBuffer deleteCharAt(int index) – удалениесимвола; StringBuffer delete(int start, int end) – удалениеподстроки; StringBuffer reverse() – обращение содержимого объекта. В классе присутствуют также методы, аналогичные методам класса String, такие как replace(), substring(), charAt(), length(), getChars() и др. В листинге 2.36 показано использование некоторых методов. Листинг 2.36 public class DemoStringBuffer { public static void main(String[] args) { StringBuffer sb = new StringBuffer(); System.out.println(" длина -> " + sb.length()); System.out.println(" размер -> " + sb.capacity()); // sb = " Java"; // ошибка, только для класса String sb.append(" Java" ); System.out.println(" строка -> " + sb); System.out.println(" длина -> " + sb.length()); System.out.println(" размер -> " + sb.capacity()); System.out.println(" реверс -> " + sb.reverse()); } } Результатом выполнения данного кода будет: длина -> 0 размер -> 16 строка -> Java длина -> 4 размер -> 16 реверс -> avaJ При создании объекта StringBuffer конструктор по умолчанию автоматически резервирует некоторый объем памяти (16 символов), что в дальнейшем позволяет быстро менять содержимое объекта, оставаясь в границах участка памяти, выделенного под объект. Размер резервируемой памяти при необходимости можно указывать в конструкторе. Если длина строки StringBuffer после изменения превышает его размер, то ёмкость объекта автоматически увеличивается, оставляя при этом резерв для дальнейших изменений. С помощью метода reverse() можно быстро изменить порядок символов в объекте. Если метод, вызываемый объектом StringBuffer, производит изменения в его содержимом, то это не приводит к созданию нового объекта, как Листинг 2.37 public class RefStringBuffer { public static void changeStr(StringBuffer s) { s.append(" Microsystems" ); } public static void main(String[] args) { StringBuffer str = new StringBuffer(" Sun" ); changeStr(str); System.out.println(str); } } В результате выполнения этого кода будет выведена строка: Sun Microsystems Объект StringBuffer передан в метод changeStr() по ссылке, поэтому все изменения объекта сохраняются и для вызывающего метода. Для класса StringBuffer не переопределены методы equals() и Листинг 2.38 public class EqualsStringBuffer { public static void main(String[] args) { StringBuffer sb1 = new StringBuffer(" Sun" ); StringBuffer sb2 = new StringBuffer(" Sun" ); System.out.print(sb1.equals(sb2)); System.out.print(sb1.hashCode() == sb2.hashCode()); } } Результатом выполнения данной программы будет дважды выведенное значениеfalse.
Задания 1).Написать класс, в котором как поле объявлен массив строк. Вводим количество строк с консоли. Организовать ввод строк с консоли до тех пор, пока в какой-то строке не встретится слово end, остальные строки заполняются цифрами = номер строки. Отсортируйте строки по длине. Определите, есть ли среди строк одинаковые. Выведите 3 последних элемента самой длинной строки. Преобразуйте 2 строку к верхнему регистру. Разделите самую длинную строку на слова. Определитьявляется ли второй символ самой короткой строки цифрой. 2). Дан массив из N строк. Строки имеют произвольную длину. Строки содержат слова, состоящие из произвольных символов, разделенных символами ' ' ', ' '.' N< =10. Необходимо написать методы: 1) сортировка строк массива по количеству слов в строке. 2) выводящий значения длин всех строк массива. 3) выводящий строки с i по j из массива. 4) выводящий номер строки с максимальной цифрой. 5) удаляющий из i-ой строки все заглавные буквы. 6) удаляющий из i-ой строки все символы не буквы и не цифры. 7) выводящий из i-ой строки все слова, содержащие только цифры. 8) вычисляющий сумму всех цифр i-ой строки. 9) выводящий из массива все слова, содержащие только прописные буквы. 10) выводящий все числа из строк. 11) удаляющий из строку часть, заключенную между двумя символами, которые вводятся (например, между скобками ‘(’ и ‘)’ или между звездочками ‘*’ и т.п.). 12) определяющий сколько в массиве одинаковых строк. 13) определяющий сколько в массиве одинаковых слов (выводить слово и количество повторений). 14) метод, объединяющий в одну строку строки с i по j. 15) метод, преобразовывающий i-ую строку так, чтобы все слова начинались с заглавной буквы. 16) метод вносящий изменение в i-ую строку (предается номер строки и новое содержание) 3). Написать класс для хранения информации о людях. В конструктор передается один параметр String, в котором через; перечисляется имя, возраст, вес, рост – пример: (" Alex; 45; 90; 185" ). В конструкторе по этому параметру заполняются соответственно 4 поля (имя, возраст, вес, рост). Метод, в который передается аналогичная строка (" Serg; 25; 80; 180" ) и делается сравнение всех полей для данного объекта с данными из строки. Метод, выводящий всю информацию об объекте. Методы для изменения каждого из полей.
Тема 2.22 Нумерованные типы
В простейшем виде механизм нумерованных типов сводится к поддержке списка именованных констант, определяющих новый тип данных. Объект нумерованного типа может принимать лишь значения, содержащиеся в списке. Таким образом, нумерованные типы предоставляют возможность создавать новый тип данных, содержащий лишь фиксированный набор допустимых значений. В повседневной жизни нумерованные типы встречается довольно часто. Например, к ним можно отнести набор денежный единиц, использующихся в стране. Месяцы в году идентифицируются именами. Так же обстоит дело с днями недели. С точки зрения программирования нумерация полезна в любом случае, когда надо определить фиксированный набор значений. Например, нумерацию можно использовать для представления набора кодов состояния (успешноезавершение, ошибка, необходимость повторной попытки). Конечно, такие значения можно определить с помощью констант, но использование нумерации – более структурированный подход. Для создания нумерованного типа используется ключевое слово enema. Ниже приведен пример простого нумерованного типа, в котором перечисляются различные транспортные средства. Листинг 2.39 public enema Transport { CAR, TRUCK, AIRPLANE, TRAIN, BOAT } Идентификаторы CAR, TRUCKи т.д. называются нумерованными константами. Каждый из них автоматически объявляется как член Transport, причем при объявлении предполагаются модификаторы publicи static. Тип этих констант соответствует типу выражения enema; в данном случае это Transport. В терминах Javaподобные константы называются самотипизированными (приставка " само" означает, что в качестве типа константы принимается тип нумерованноговыражения). Определив нумерацию, можно создать переменную данного типа. Однако, несмотряна то, что для поддержки нумерации используется класс, сформировать экземпляр enum с помощью оператора new невозможно. Переменная нумерованного типа создается подобно переменной одного из простых типов. Например, чтобы объявить переменную tpрассмотренного выше типа Transport, надо использовать выражение Transporttp; Поскольку переменная tpпринадлежит типу Transport, ей можно присваивать только те значения, которые определены в составе нумерации. Например, в следующей строке кода данной переменной: присваивается значение AIRPLANE. tp = Transport.AIRPLANE; Обратите внимание на то, что имя AIRPLANEсоответствует типу Transport. Для проверки равенства нумерованных констант служит оператор сравнения ==. Например, приведенное ниже выражение сравнивает содержимое переменной tpс константой TRAIN. if(tp == Transport.TRAIN) //... Нумерованное значение также можно использовать в выражении switch. Очевидно, что при этом в выражениях case могут присутствовать только константы из того же выражения enum, которому принадлежит константа, указанная в выражении switch. Например, следующий фрагмент кода составлен корректно: // Использование нумерованного типа в выражении switch(tp) { caseCAR: System.out.println(" A car carries people." ); break; caseTRUCK: System.out.println(" A truck carries freight." ); break; caseAIRPLANE: System.out.println(" An airplane flies." ); break; caseTRAIN: System.out.println(" A train runs on rails." ); break; caseBOAT: System.out.println(" A boat sails on water." ); break; } Заметьте, что в выражениях case используются константы без указания имени типа. Например, вместо Transport.TRUCKуказано просто TRUCK. Это допустимо потому, что нумерованный тип в выражении switchнеявно определяет тип констант. Более того, если вы попытаетесь явно указать тип константы, возникнет ошибка компиляции. Популярное:
|
Последнее изменение этой страницы: 2016-05-30; Просмотров: 830; Нарушение авторского права страницы