Массив (array) – это упорядоченный набор одинаково устроенных ячеек, доступ к которым осуществляется по индексу. Например, если у массива имя a1, то a1[i] – имя ячейки этого массива, имеющей индекс i.
В Java массивы являются объектами, но особого рода – их объявление отличается от объявления других видов объектов. Переменная типа массив является ссылочной – в ней содержится адрес объекта, а не сам объект, как и для всех других
Тип ячейки массива называется базовым типом для массива.
Для задания массива, в отличие от объектов других типов, не требуется предварительно задавать класс, и иметь специальное имя для данного
Например, объявление
int[] a1;
задает переменную a1 типа массив. При этом размер массива (число ячеек в нем) заранее не задается и не является частью типа.
Для того, чтобы создать объект типа массив, следует воспользоваться зарезервированным словом new, после чего указать имя базового типа, а за ним в квадратных скобках число ячеек в создаваемом массиве:
a1=new int[10];
Можно совместить объявление типа переменной и
int[] a1=new int[10];
После null.
Ячейки в массиве имеют индексы, всегда начинающиеся с нуля. То есть первая ячейка имеет номер 0, вторая – номер 1, и так далее. Если n, то последняя ячейка имеет индекс n-1. Такая своеобразная нумерация принята в языках C и C++, и язык Java унаследовал эту не очень привлекательную особенность, часто приводящую к ошибкам при организации циклов.
Длина массива хранится в поле length, которое доступно только по чтению – изменять его путем присваивания нового значения нельзя.
Пример работы с массивом:
int[] a=new int[100];
for(int i=0;i<a.length;i++){
a[i]=i+1;
};
Если у нас имеется переменная типа массив, и ей сопоставлен массив заданной длины, в любой момент этой переменной можно сопоставить новый массив. Например,
a1=new int[20];
При этом прежний объект-массив, находящийся в динамической области памяти, будет утерян и превратится в мусор.
Переменные типа массив можно присваивать друг другу. Например, если мы задали переменную
int[] a2;
то сначала в ней хранится значение null (ссылка направлена "в никуда"):
(рис 7.1) Массив с ячейками типа intПрисваивание
a2=a1;
приведет к тому, что ссылочные переменные a1 и a2 будут ссылаться на один и тот же массив, расположенный в динамической области памяти.
(рис 7.2) Массив с ячейками типа intТо есть присваивание переменных типа массив приводит к тому, что имена переменных становятся синонимами одного и того же массива – копируется адрес массива. А вовсе не приводит к копированию элементов из одного массива в другой, как это происходит в некоторых других языках программирования.
В качестве элементов массивов могут выступать объекты. В этом случае доступ к полям и методам этих объектов производится через имя ячейки массива, после которого через точку указывается имя поля или метода. Например, если у нас имеется класс Circle ("окружность"), у которого имеются поля x, y и r, а также методы show() и hide(), то массив circles из 10 объектов такого типа может быть задан и инициализирован, например, так
int n=10;
Circle[] circles=new Circle[n];
for(int i=0;i<n;i++){
circles[i]=new Circle();
circles[i].x=40*i;
circles[i].y= circles[i].x/2;
circles[i].r=50;
circles[i].show();
};
В такого рода программах для повышения читаемости часто применяется использование вспомогательной ссылки, позволяющей избежать многократного обращения по индексу. В нашем случае мы будем использовать в этих целях переменную circle. На скорости работы программы это почти не сказывается (хотя и может чуть повысить быстродействие), но делает код более читаемым:
int n=10;
Circle[] circles=new Circle[n];
Circle circle;
for(int i=0;i<n;i++){
circle=new Circle();
circle.x=40*i;
circle.y= circles[i].x/2;
circle.r=50;
circle.show();
circles[i]= circle;
};
С помощью переменной circle мы инициализируем создаваемые объекты и показываем их на экране, после чего присваиваем ссылку на них ячейкам массива.
int[][] a=new int[10][20];
Будет задана ячейка типа "int[], а для ячеек по второму индексу int.
Рассмотрим работу с двумерными массивами на примере заполнения двумерного массива случайными числами:
int m=10;//10 строк
int n=20;//20 столбцов
int[][] a=new int[m][n];
for(int i=0;i<m;i++){ //цикл по строкам
for(int j=0;j<n;j++){ //цикл по столбцам
a[i][j]=(int)(100*Math.random());
System.out.print(a[i][j]+" ");
};
System.out.println();//перевод на новую строку после вывода строки матрицы
};
Многомерные массивы задаются аналогично двумерным – только указывается необходимое количество прямоугольных скобок. Следует отметить, что массивы размерности больше 3 используют крайне редко.
Обычно в двумерных и многомерных массивах задают одинаковый размер всех массивов, связанных с ячейками по какому-либо индексу. Такие массивы называют регулярными. В Java, в отличие от большинства других языков программирования, можно задавать массивы с разным размером массивов, связанных с ячейками по какому-либо индексу. Такие "непрямоугольные" массивы называют иррегулярными. Обычно их используют для экономии памяти. При работе с иррегулярными массивами следует быть особенно аккуратными, так как разный размер "вложенных" массивов часто приводит к ошибкам при реализации алгоритмов.
Пример задания иррегулярного двумерного массива треугольной формы:
int n=9;
int[][] a=new int[n][];
for(int i=0;i<a.length;i++){ //цикл по строкам
a[i]=new int[i+1]; //число элементов в строке равно i+1
for(int j=0;j<a[i].length;j++){ //цикл по столбцам
a[i][j]=100*i+j;
System.out.print(a[i][j]+" ");
};
System.out.println();//перевод на новую строку после вывода строки матрицы
};
После
int[] a=new int[4]; a[0]=2; a[1]=0; a[2]=0; a[3]=6;
Но гораздо удобнее следующий вариант синтаксиса:
int[] a=new int[] {2,0,0,6};
При этом приходится задавать массив без указания его размера непосредственно с помощью указания значений в фигурных скобках:
В правой части оператора присваивания стоит так называемый анонимный массив – у него нет имени. Такие массивы обычно используют для инициализации, а также при написании кода для различного рода проверок.
Если мы хотим присвоить новые значения, приходится либо присваивать поэлементно, либо создавать новый объект:
a=new int[] {2,0,0,6};
При инициализации двумерных и многомерных массивов используют вложенные массивы, задаваемые с помощью фигурных скобок. Например, фрагмент кода
int[][] b= new int[][]
{
{2,0,0,0}, //это b[0]
{2,0,0,1}, //это b[1]
{2,0,0,2}, //это b[2]
{1,0,0,0}, //это b[3]
{2,0,0,0}, //это b[4]
{3,0,0,0}, //это b[5]
};
приведет к заданию целочисленного двумерного массива b, состоящего из 6 строк и 4 столбцов, т.е. int[6][4]. Таким образом можно задавать как регулярные, так и иррегулярные массивы. Но следует помнить, что в таком варианте синтаксиса проверки правильности размера массива по индексам не делается, что может привести к ошибкам. Например, следующий код при компиляции не выдаст ошибки, а будет создан иррегулярный массив:
int[][] b= new int[][]
{
{2,0,0,0}, //это b[0]
{2,0,0,1}, //это b[1]
{2,0,0,2}, //это b[2]
{1,0,0,0}, //это b[3]
{2,0,0,0}, //это b[4]
{3,0,0}, //это b[5] – массив из трех элементов
};
Из объектов-массивов можно вызывать метод , позволяющий создавать копию (клон) массива:
a=new int[] {2,0,0,6};
int[] a1=a.clone();
Напомним, что присваивание
int[] b=a;
не приведет к копированию массива – просто переменная b станет ссылаться на тот же объект-массив. Копирование массивов можно осуществлять в цикле, но гораздо быстрее использовать метод System.arraycopy.
int[] b=new int[a.length+10]; System.arraycopy(a,index1a,b, index1b,count);
Из a в b копируется count элементов начиная с индекса index1a в массиве a. Они размещаются в массиве b начиная с индекса index1b. Содержимое остальных элементов b не меняется. Для использования метода требуется, чтобы массив b существовал и имел необходимую длину - при выходе за границы массивов возбуждается исключительная ситуация.
Быстрое заполнение массива одинаковыми значениями может осуществляться методом Arrays.fill(массив, значение). Класс Arrays расположен в пакете java.util.
Поэлементное Arrays.equals(a,a1). Заметим, что у любого массива имеется метод equals, унаследованный от класса Object и позволяющий сравнивать массивы. Но, к сожалению, метод не переопределен, и сравнение идет по адресам объектов, а не по содержимому. Поэтому a.equals(a1) это то же самое, что a==a1. Оба сравнения вернут false, так как адреса объектов, на которые ссылаются переменные a и a1, различаются. Напротив, сравнения a.equals(a3) и a==a3 вернут true, так как a и a3 ссылаются на один и тот же объект-массив.
Сортировка (упорядочение по значениям) массива a производится методами Arrays.sort(a) и Arrays.sort(a,index1,index2). Первый из них упорядочивает в порядке возрастания весь массив, второй – часть элементов (от индекса index1 до индекса index2 ). Имеются и более сложные методы сортировки. Элементы массива должны быть сравниваемы (поддерживать операцию сравнения).
Arrays.deepEquals(a1,a2) – сравнение на равенство содержимого a1 и a2 путем глубокого сравнения (на равенство содержимого, а не ссылок – на произвольном уровне вложенности).
Также в классе Arrays содержится большое число других полезных методов.
В Java получили широкое использование коллекции (Collections) – "умные" массивы с динамически изменяемой длиной, поддерживающие ряд важных дополнительных операций по сравнению с массивами. Базовым для иерархии коллекций является класс java.util.AbstractCollection. (В общем случае класс коллекции не обязан быть потомком AbstractCollection – он может является любым классом, реализующим интерфейс Collection ). Основные классы и интерфейсы коллекций:
Set, SortedSet ; классы HashSet, TreeSet, EnumSet, LinkedHashSet — множества (неупорядоченные или некоторым образом упорядоченные наборы неповторяющихся элементов);java.util.List ; классы java.awt .List, ArrayList , LinkedList, Vector — списки (упорядоченные наборы элементов, причем элементы могут повторяться в разных местах списка);Map, SortedMap ; классы HashMap, HashTable , ConcurrentHashMap, TreeMap, EnumMap, Properties — таблицы (списки пар "имя-значение").Доступ к элементам коллекции в общем случае не может осуществляться по индексу, так как не все коллекции поддерживают индексацию элементов. Эту функцию осуществляют с помощью специального объекта – ). У каждой коллекции collection имеется свой
Iterator iter = collection.iterator()
У итераторов имеются следующие три метода:
boolean hasNext() - дает информацию, имеется ли в коллекции следующий объект.Object next() – возвращает ссылку на следующий объект коллекции.void remove() – удаляет из коллекции текущий объект, то есть тот, ссылка на который была получена последним вызовом next().Пример преобразования массива в коллекцию и цикл с доступом к элементам этой коллекции, осуществляемый с помощью
java.util.List components= java.util.Arrays.asList(this.getComponents());
for (Iterator iter = components.iterator();iter.hasNext();) {
Object elem = (Object) iter.next();
javax.swing.JOptionPane.showMessageDialog(null,"Компонент: "+
elem.toString());
}
| Имя метода | Действие |
|---|---|
boolean add(Object obj) |
Добавление объекта в коллекцию (в конец списка). Возвращает true в случае успешного добавления - изменения коллекции. Коллекция может не позволить добавление элементов несовместимого типа или не подходящих по какому-либо другому признаку. |
boolean addAll(Collection c) |
Добавление в коллекцию всех объектов из другой коллекции. Возвращает true в случае успешного добавления, то есть если добавлен хотя бы один элемент. |
void clear() |
Очистка коллекции - удаление из нее ссылок на все входящие в коллекцию объекты. При этом те объекты, на которые имеются ссылки у других элементов программы, не удаляются из памяти. |
boolean contains(Object obj) |
Возвращает true в случае, если коллекция содержит объект obj. Проверка осуществляется с помощью поочередного вызова метода obj.equals(e) для элементов e, входящих в коллекцию. |
boolean containsAll(Collection c) |
Возвращает true в случае, если коллекция содержит все элементы коллекции c. |
boolean |
Возвращает true в случае, если коллекция пуста, то есть не содержит ни одного элемента. |
|
Возвращает ссылку на next() дает ссылку на начальный элемент коллекции. |
boolean remove(Object obj) |
Удаляет из коллекции первое встретившееся вхождение объекта obj. Поиск и удаление осуществляется с помощью true в случае, если удаление удалось, то есть если коллекция изменилась. |
boolean removeAll(Collection c) |
Удаляет из коллекции все элементы коллекции c. Возвращает true в случае, если удаление удалось, то есть если коллекция изменилась. |
boolean retainAll(Collection c) |
Оставляет в коллекции только те из входящих в нее элементов, которые входят в коллекцию c. |
int size() |
Возвращает число элементов в коллекции. |
Object[] toArray() |
Возвращает массив ссылок на объекты, содержащиеся в коллекции. То есть преобразует коллекцию в массив. |
T[] toArray(T[n] a) |
Возвращает массив элементов типа T, полученных в результате преобразования элементов, содержащихся в коллекции. То есть преобразует коллекцию в массив. Если число элементов коллекции не превышает размер n массива a, размещение данных производится в существующих ячейках памяти, отведенных под массив. Если превышает n – в памяти динамически создается и заполняется новый набор ячеек, и их число делается равным числу элементов коллекции. После чего переменная a начинает ссылаться на новый набор ячеек. |
String toString() |
Метод переопределен – он возвращает строку со списком элементов коллекции. В списке выводятся заключенные в квадратные скобки строковые представления элементов, разделяемые комбинацией "," – запятая с пробелом после нее. |
Самыми распространенными вариантами коллекций являются списки ( Lists ). Они во многом похожи на массивы, но отличаются от массивов тем, что в списках основными операциями являются добавление и удаление элементов. А не доступ к элементам по индексу, как в массивах.
В классе List имеются методы коллекции, а также ряд дополнительных методов:
list.get(i) – получение ссылки на элемент списка list по индексу i.list.indexOf (obj) - получение индекса элемента obj в списке list. Возвращает -1 если объект не найден.list.listIterator() – получение ссылки на ListIterator, обладающего дополнительными методами по сравнению с Iterator .list.listIterator(i) – то же с позиционированием i.list.remove(i) – удаление из списка элемента с индексом i.list.set(i,obj) – замена в списке элемента с индексом i на объект obj.list.subList (i1,i2) – возвращает ссылку на подсписок, состоящий из элементов списка с индексами от i1 до i2.Кроме них в классе List имеются и многие другие полезные методы.
Ряд полезных методов для работы с коллекциями содержится в классе Collections:
Collections.addAll(c,e1,e2,…,eN) - добавление в коллекцию c произвольного числа элементов e1,e2,…,eN.Collections.frequency (c,obj) – возвращает число вхождений элемента obj в коллекцию c.Collections.reverse(list) – обращает порядок следования элементов в списке list (первые становятся последними и наоборот).Collections.sort(list) – сортирует список в порядке возрастания элементов. Сравнение идет вызовом метода e1.compareTo(e2) для очередных элементов списка e1 и e2.Кроме них в классе Collections имеются и многие другие полезные методы.
В классе Arrays имеется метод
Arrays.asList(a) – возвращает ссылку на список элементов типа T, являющийся оболочкой над массивом T[] a. При этом и массив, и список содержат одни и те же элементы, и изменение элемента списка приводит к изменению элемента массива, и наоборот.Класс String инкапсулирует действия со строками. Объект типа String - строка, состоящая из произвольного числа символов, от 0 до $$2*10^9$$. Литерные константы типа String представляют собой последовательности символов, заключенные в двойные кавычки: "A", "
Это так называемые "длинные" строки. Внутри литерной строковой константы не разрешается использовать ряд символов - вместо них применяются управляющие последовательности.
Внутри строки разрешается использовать переносы на новую строку. Но литерные константы с такими переносами запрещены, и надо ставить "\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 могут быть использованы значения "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, и преобразованными к нижнему регистру (строчным буквам). Имеется вариант метода, делающего такое преобразование с учетом конкретной кодировки ( 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". Совершенно так же выполняется
Еще более странный результат получится при присваивании
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, ) с помощью метода :
Byte.decode ( строка ) , и т.п.Также полезны методы для анализа отдельных символов:
Character.isDigit ( символ ) – булевская функция, проверяющая, является ли символ цифрой.Character.isLetter ( символ ) – булевская функция, проверяющая, является ли символ буквой.Character.isLetterOrDigit ( символ ) – булевская функция, проверяющая, является ли символ буквой или цифрой.Character.isLowerCase ( символ ) – булевская функция, проверяющая, является ли символ символом в нижнем регистре.Character.isUpperCase ( символ ) – булевская функция, проверяющая, является ли символ символом в верхнем регистре.Character.isWhitespace ( символ ) – булевская функция, проверяющая, является ли символ "пробелом в широком смысле" – пробелом, символом табуляции, перехода на новую строку и т.д.Для того чтобы сделать работу с многочисленными присваиваниями более эффективной, используются классы StringBuffer и StringBuilder. Они особенно удобны в тех случаях, когда требуется проводить изменения внутри одной и той же строки (убирать или вставлять символы, менять их местами, заменять одни на другие). Изменение значений переменных этого класса не приводит к созданию мусора, но несколько медленнее, чем при работе с переменными типа String. Класс StringBuffer рекомендуется использовать в тех случаях, когда используются потоки ( threads ) – он, в отличие от классов String и StringBuilder, обеспечивает синхронизацию строк. Класс StringBuilder, введенный начиная с
К сожалению, совместимости по присваиванию между переменными этих классов нет, как нет и возможности преобразования этих типов. Но в классах 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);
Буферизуемые и обычные строки можно сравнивать на совпадение содержания: s1.contentEquals(sb) – булевская функция, возвращающая true в случае, когда строка s1 содержит такую же последовательность символов, как и строка sb.
Вывод графики осуществляется с помощью объектов типа java.. Для них определен ряд методов, описанных в следующей далее таблице.
Подразумевается, что 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) ;
|
Вывод многоугольника по массиву точек, 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 и другие перегруженные варианты метода |
Вывод изображения. |
| Рисование заполненных фигур | |
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)
|
Вывод многоугольника, заполненного текущим цветом. |
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)
|
Установка новых границ области вывода. Вне этой области при выводе графических примитивов они усекаются (не выводятся). |
clipRect(x,y,w,h) |
Сужение области вывода. |
Rectangle getClipBounds()
|
Возвращает параметры прямоугольника, в который вписана область вывода. |
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<=100;i++){
FiguresUtil.moveFigureBy(figure,dx,dy);
update(g);
};
При работе со статическими изображениями изложенных алгоритмов вполне достаточно. Однако при использовании движущихся элементов во многих
При работе программы выполнение операторов обычно идет в рамках "основного ствола" - в случае, когда все идет как надо. Но время от времени возникают исключительные ситуации ( исключения - exceptions), приводящие к ответвлению от основного ствола: деление на 0, отсутствие места на диске или попытка писать на защищенную для записи дискету, ввод с клавиатуры ошибочного символа (например, буквы вместо цифры). В отличие от катастрофических ситуаций (ошибок) такие ситуации в большинстве случаев могут быть учтены в программе, и, в частности, они не должны приводить к аварийному завершению программы.
В языках программирования предыдущих поколений для решения указанных проблем приходилось использовать огромное число проверок на допустимость присваиваний и математических операций. Мало того, что эти проверки резко замедляли работу программы - не было гарантии, что они достаточны, и что во время работы программы не возникнет "вылет" из-за возникновения непредусмотренной ситуации.
В Java, как и в других современных языках программирования, для таких целей предусмотрено специальное средство — обработка исключительных ситуаций. При этом используется так называемый защищенный блок программного кода try ("попытаться"), после которого следует необязательные блоки перехвата исключений catch, за которыми идет необязательный блок очистки ресурсов finally.
Про наступившую исключительную ситуацию говорят, что она возникает, либо – что она возбуждается. В английском языке для этого используется слово throw – "бросить". Поэтому иногда в переводной литературе используют дословный перевод "бросается исключительная ситуация".
Общий случай использования защищенного блока программного кода и перехвата исключительных ситуаций выглядит так:
try{
операторы0;
}
catch (ТипИсключения1 переменная1){
операторы1;
}
catch (ТипИсключения2 переменная2){
операторы2;
}
catch (ТипИсключенияN переменнаяN){
операторыN;
}
finally{
операторы;
}
Отметим, что при задании блоков try-catch-finally после фигурных скобок точку с запятой ";" можно не ставить, как и всегда в случае использования фигурных скобок. Но можно и ставить - по усмотрению программиста.
Если исключительных ситуаций не было, операторы0 в блоке try выполняются в обычном порядке, после чего выполняются операторы в блоке finally. Если же возникла исключительная ситуация в блоке try, выполнение блока прерывается, и идет перехват исключений в блоках catch ("перехватить"). В качестве параметра оператора catch задается ссылочная переменная, имеющая тип той исключительной ситуации, которую должен e (по первой букве от exception). Если catch не делается.
После проверок и, возможно, перехвата исключения в блоках catch выполняются операторы блока finally. Его обычно используют для высвобождения ресурсов, и поэтому часто называют блоком "очистки ресурсов". Специальных операторов или зарезервированных конструкций для обработки в блоке finally нет. Отличие кода внутри блока finally от кода, стоящего после оператора try…finally, возникает только при наличии внутри блоков try или catch операторов break, continue, return или System.exit, то есть операторов, прерывающих работу блока программного кода. В этом случае независимо от их срабатывания или несрабатывания сначала происходит выполнение операторов блока finally, и только потом происходит переход в другое место программы в соответствии с оператором прерывания.
Пример обработки исключений:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(ArithmeticException e){
System.out.println("Деление на ноль");
} catch(NumberFormatException e){
System.out.println("Корень из отрицательного числа!");
}
};
Исключительные ситуации в Java являются объектами. Их типы являются классами-потомками Throwable (от throw able – "способный возбудить исключительную ситуацию"). От Throwable наследуются классы Error ("Ошибка") и Exception ("Исключение"). Экземплярами класса Error являются непроверяемые исключительные ситуации, которые невозможно перехватить в блоках catch. Такие исключительные ситуации представляют катастрофические ошибки, после которых невозможна нормальная работа приложения. Экземплярами класса Exception и его потомков являются проверяемые исключительные ситуации. Кроме одного потомка – класса RuntimeException (и его потомков). Имя этого класса переводится как "Исключительные ситуации времени выполнения".
Классы исключительных ситуаций либо предопределены в стандартных пакетах (существуют исключительные ситуации ArithmeticException для арифметических операций в пакете java.lang, IOException в пакете java.io, и так далее), либо описываются пользователем как потомки класса Exception или его потомков.
В Java типы-исключения принято именовать, оканчивая имя класса на "Exception" ("Исключение") для "Error" ("Ошибка") для непроверяемых.
По правилу catch имеет большое значение: обработчик исключения более общего типа следует писать всегда после обработчика для его типа-потомка, иначе обработчик потомка никогда не будет вызван.
В приведенном выше примере вместо NumberFormatException можно поставить Exception, так как других типов исключений кроме NumberFormatException сюда доходить не может. В этом случае метод выглядит так:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(ArithmeticException e){
System.out.println("Деление на ноль");
} catch(Exception e){
System.out.println("Корень из отрицательного числа!");
}
};
Но если бы мы попробовали таким же образом заменить catch, то блок для исключений типа Exception всегда перехватывал бы управление, и обработчик для NumberFormatException никогда бы не срабатывал. Пример такого неправильно написанного кода:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(Exception e){
System.out.println("Деление на ноль");
} catch(NumberFormatException e){
System.out.println("Корень из отрицательного числа!");
}
};
В таких случаях среда разработки NetBeans выдаст сообщение вида "exception java.lang.NumberFormatException has already been caught" – "исключение java.lang.NumberFormatException уже было перехвачено".
Для того чтобы задать собственный тип исключительной ситуации, требуется задать соответствующий класс. Он должен быть наследником от какого-либо класса исключительной ситуации.
Например, зададим
class WrongPasswordException extends Exception {
WrongPasswordException(){ // конструктор
System.out.println("Wrong password!");
}
}
Создание объекта-исключения может проводиться в произвольном месте программы обычным образом, как для всех объектов, при этом возбуждения исключения не происходит.
Программное возбуждение исключительной ситуации производится с помощью оператора throw, после которого указывается оператор создания объекта-исключения:
throw new ТипИсключения();
Например,
throw new WrongPasswordException();
Если после частичной обработки требуется повторно возбудить исключительную ситуацию e, используется вызов
throw e;
Для finally, если он есть, и всплывание продолжается – происходит выход из текущего метода в метод более высокого уровня. Соответственно, исключение начинает обрабатываться на уровне этого метода. Если оно не перехватывается, происходит выход на еще более высокий уровень, и так далее.
Если в методе исключение данного типа перехватывается, всплывание прекращается. Если же ни на каком уровне исключение не перехвачено – оно обрабатывается исполняющей средой. При этом выполняются действия, предусмотренные в конструкторе исключения, а затем система выводит служебную информацию о том, где и какого типа исключение возникло.
Исключительная ситуация – это особая, экстремальная ситуация, не планируемая заранее. Не следует использовать исключения в качестве конструкций, на которых основаны часто повторяющиеся в программе действия.
Задание: усовершенствовать класс WrongPasswordException таким образом, чтобы сообщение об ошибке появлялось в виде диалогового окна.
Формат
Модификаторы Тип Имя(список параметров)
throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN
{
Тело функции
}
Аналогичным образом объявляется конструктор, который может возбуждать проверяемые исключительные ситуации:
Модификаторы ИмяКласса(список параметров)
throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN
{
Тело конструктора
}
Слово throws означает "возбуждает исключительную ситуацию" (дословно – "бросает").
throws в заголовке метода указывать не надо.
Если в теле реализуемого метода используется вызов метода, который может возбуждать исключительную ситуацию, и это исключение не перехватывается, в заголовке реализуемого метода требуется указывать соответствующий тип возбуждаемого исключения. Если же это исключение порождается внутри защищенного блока программного кода, и в каком-либо блоке catch перехватывается этот
Как мы уже знаем, в throw, возбуждающий исключительную ситуацию. В этом случае если объект-исключение не перехвачен, в заголовке метода требуется указывать соответствующий тип возбуждаемого исключения. В частности, оператор throw может быть использован для порождения исключения другого типа после обработки перехваченного исключения в блоке catch.
Если в
Пример: проверка пароля, введенного пользователем.
class CheckPasswordDemo{
private String password="";
public String getPassword(){
return password;
};
public void setPassword(){
...//реализация метода
};
public void checkPassword(String pass)
throws WrongPasswordException {
if(!pass.equals(password))
throw new WrongPasswordException();
};
}
При вызове метода checkPassword в случае неправильного пароля, переданного в качестве параметра, возбуждается исключительная ситуация. Следует обратить внимание, что сравнение pass!=password всегда будет давать true, так как строки сравниваются как объекты. То есть при сравнении "==" проверяется идентичность адресов в памяти, а не содержание строк.
Еще один момент, на котором следует остановиться: не используйте else в операторе if! Возбуждение исключения выполняется намного дольше, потребляет много ресурсов и при неудачном использовании только ухудшает программу. Например, в нашем случае имело бы смысл при неправильном вводе пароля предусмотреть возможность еще двух попыток ввода в обычном режиме – и только после третьей неудачной попытки возбуждать исключение.
Концепция работы с файлами в Java включает две составляющие:
File.Обеспечивает работу с именами файлов (проверка существования файла или папки с заданным именем, нахождение абсолютного пути по относительному и наоборот, проверка и установка
Обеспечивает работу не только с файлами, но и с памятью, а также различными устройствами ввода-вывода.
Объекты типа File могут рассматриваться как абстракции, инкапсулирующие работу с именами файлов и папок. При этом папка рассматривается как разновидность файла, обладающая особыми атрибутами.
Создание объекта типа File осуществляется с помощью конструкторов, имеющих следующие варианты:
При этом имена могут быть как короткими (локальными), без указания пути к файлу или папке, так и длинными (абсолютными), с указанием пути. В приведенной далее таблице файлы (папки) ищутся по имени в соответствии с правилами поиска файлов в операционной системе. Для платформы Windows® вместо символа "\" в строках, соответствующих путям, должна использоваться последовательность "\\".
Важнейшие файловые операции, инкапсулированные классом File:
| Поле или метод | Что содержит или делает |
|---|---|
| Переменные класса | |
String pathSeparator |
Содержит строку с символом разделителя пути в операционной системе. Это "/" в Unix-подобных системах и "\" в Windows®. |
char pathSeparatorChar |
Содержит символ разделителя пути в операционной системе. Это '/' в Unix-подобных системах и '\' в Windows®. |
String separator |
Содержит строку с символом разделителя между именами файлов и файловых масок в операционной системе. |
char separatorChar |
Содержит символ разделителя между именами файлов и файловых масок в операционной системе. |
| Проверка параметров файла или папки | |
boolean exists() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует. Иначе false. |
long length() |
Возвращает длину файла в байтах в случае, когда файл с заданным в конструкторе именем существует и не является папкой. Иначе 0L. |
boolean canRead() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует и доступен по чтению. Иначе false. (В Unix-подобных системах существуют файлы, доступные только по записи). Может возбуждать SecurityException. |
boolean setReadOnly() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует, и ему удалось установить статус "доступен только по чтению". Иначе false. |
boolean canWrite() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует и доступен по записи. Иначе false. (В операционных системах существуют файлы, доступные только по чтению). Может возбуждать SecurityException. |
boolean isDirectory() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является папкой. Иначе false. |
boolean isFile() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является файлом. Иначе false. |
boolean isHidden() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является скрытым. Иначе false. В Unix-образных системах скрытыми являются файлы, имена которых начинаются с точки. В Windows® – те, которые имеют атрибут "hidden" ("скрытый"). |
long lastModified() |
Возвращает время последней модификации файла, если он существует и доступен по чтению. Иначе 0L. Время отсчитывается в миллисекундах, прошедших с 0 часов 1 января 1970 года (по Гринвичу). |
boolean setLastModified(long time) |
Устанавливает время последней модификации файла. Возвращает true, если он существует и доступен по записи. Иначе false. Время отсчитывается в миллисекундах, прошедших с 0 часов 1 января 1970 года (по Гринвичу). |
| Путь и имя файла (папки) | |
String getName() |
Возвращает короткое имя файла или папки. |
String getParent() |
Возвращает абсолютное имя родительской папки – то есть папки, в которой находится файл (или папка), соответствующий файловому объекту. |
String getAbsolutePath() |
Возвращает абсолютный путь к файлу или папке, включая имя файла. При этом если в имени файла в конструкторе была задана |
String getCanonicalPath() |
Возвращает абсолютный путь к файлу или папке, включая имя файла. При этом если в имени файла в конструкторе была задана IOException, если канонический путь не может быть построен. |
int compareTo(File f) |
Сравнение имен файлов (папок), сопоставляемых текущему файловому объекту и объекту f. Возвращает 0 в случае, когда абсолютные имена файлов (папок) совпадают. Иначе возвращает число, зависящее от разницы в длинах имен и кодов составляющих их символов. Сравнение зависимо от операционной системы – в Unix-образных системах регистр символов имеет значение, в Windows® – не имеет. Соответствие понимается абстрактно на уровне имен и путей – самих файлов может не существовать. |
boolean isAbsolute() |
Возвращает true в случае, когда адресация к имени файла (папки) текущего файлового объекта является абсолютной. Хотя может содержать элементы относительной адресации, то есть не быть канонической. |
boolean equals(Object obj) |
Возвращает true тогда и только тогда, когда текущий объект и параметр obj соответствуют одному и тому же файлу (папке) . С учетом правил о путях и регистрах символов, задаваемых операционной системой. Соответствие понимается абстрактно на уровне имен и путей – самих файлов может не существовать. |
| Создание/уничтожение/переименование файлов и папок | |
boolean createNewFile() |
Попытка создания файла или папки по имени, которое было задано в конструкторе объекта. В случае успеха возвращается true, иначе false. Возбуждает IOException, если файл не может быть создан (например, уже существует). |
File createTempFile(String
|
Метод класса. Обеспечивает создание пустого файла (или папки), задаваемого коротким именем в папке операционной системы, предназначенной для временных файлов. Возвращает ссылку на объект. Префикс должен быть не менее 3 символов. Возбуждает IOException, если файл не может быть создан (например, уже существует). |
boolean mkdir() |
Попытка создания папки по имени, которое было задано в конструкторе объекта. Возвращает true в случае успешного создания и false в других случаях. |
boolean mkdirs() |
Попытка создания папки по имени, которое было задано в конструкторе объекта, причем заодно создаются все папки, заданные в пути, если они не существовали. Возвращает true в случае успешного создания и false в других случаях. |
boolean delete() |
Попытка удаления файла или папки по имени, которое было задано в конструкторе объекта. Возвращает true в случае успешного удаления и false в других случаях. |
boolean renameTo(File dest) |
Попытка переименования файла или папки с имени, которое было задано в конструкторе объекта, на новое, задаваемое параметром dest. Возвращает true в случае успешного переименования и false в других случаях. |
| Создание нового файлового объекта с помощью имеющегося | |
File getAbsoluteFile() |
Создание нового файлового объекта по абсолютному пути, соответствующему текущему файловому объекту. |
File getCanonicalFile() |
Создание нового файлового объекта по каноническому пути, соответствующему текущему файловому объекту. Возбуждает IOException, если канонический путь не может быть построен. |
File getParentFile() |
Создание нового файлового объекта по абсолютному пути, соответствующему родительской папке для текущего файлового объекта. |
| Списки папок и файлов | |
String[] list()
|
Возвращает массив строк (список) коротких имен находящихся в папке файлов и папок. Имена элементов, находящихся во null. При наличии фильтра возвращаются только те имена, которые соответствуют маске фильтра. |
File[] listFiles()
|
Возвращает массив файловых объектов, соответствующих находящимся в папке файлов и папок. Элементы, находящиеся во null. При наличии фильтра возвращаются объекты только для тех имен, которые соответствуют маске фильтра. |
File[] listRoots() |
Возвращает массив файловых объектов, соответствующих возможным на данном компьютере корневым папкам. В Unix это папка "/", в Windows® – корневые папки всех возможных дисков. |
Пример работы с файловыми объектами:
File f1=new File(".."); // "." , "/" , "C:/../"
System.out.println("getAbsolutePath(): "+f1.getAbsolutePath());
try{
System.out.println("getCanonicalPath(): "+f1.getCanonicalPath());
}
catch(Exception e){
System.out.println("Исключение от getCanonicalPath() ");
};
System.out.println("exists(): "+f1.exists());
System.out.println("canRead(): "+f1.canRead());
System.out.println("canWrite(): "+f1.canWrite());
При работе с файлами в подавляющем большинстве приложений требуется вызов файлового диалога. В нашем приложении из JLabel ("Метка") – первый компонент в палитре . А затем повторим эту операцию еще раз. В первой метке мы будем показывать имя выбранного файла, а во второй – путь к этому файлу.
Для того, чтобы вызвать файловый диалог, назначим обработчик события пункту файлового меню openMenuItem ("Открыть...") – подузел [JFrame]/menuBar[JMenu]/fileMenu[JMenu]/openMenuItem[JMenuItem]. Двойной щелчок по узлу openMenuItem приводит к автоматическому созданию заготовки обработчика openMenuItemActionPerformed и открытию редактора исходного кода.
Сначала мы создаем в приложении объект типа JFileChooser, соответствующий файловому диалогу. Если в начале записать import javax., что желательно, то в соответствующих местах кода не потребуется квалификация javax.. Но в данном примере импорт не сделан намеренно для того, чтобы было видно, где используются классы данного пакета.
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();
Добавим в обработчик необходимый код:
private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
if(fileChooser.showOpenDialog(null)!= fileChooser.APPROVE_OPTION){
System.out.println("Отказались от выбора");
return;
};
System.out.println("Нажали Open");
jLabel1.setText(fileChooser.getSelectedFile().getName());
jLabel2.setText(fileChooser.getSelectedFile().getParent());
}
В первой строке обработчика вызывается метод fileChooser.showOpenDialog(openMenuItem). Он показывает диалог на экране. В качестве параметра должен быть задан родительский компонент – в этом качестве мы используем пункт меню openMenuItem. Сравнение с APPROVE_OPTION позволяет выяснить, была ли выбрана кнопка Open - "Открыть".
Следует обратить внимание на характерный прием – выход из подпрограммы с помощью оператора return в случае, когда не был осуществлен выбор файла. Неопытные программисты написали бы данный фрагмент кода таким образом:
if(fileChooser.showOpenDialog(openMenuItem)== fileChooser.APPROVE_OPTION){
System.out.println("Нажали Open");
jLabel1.setText(fileChooser.getSelectedFile().getName());
jLabel2.setText(fileChooser.getSelectedFile().getParent());
}
else
System.out.println("Отказались от выбора");
На первый взгляд принципиальной разницы нет. Но при усовершенствовании программы код, соответствующий выбору файла с помощью диалога, заметно разрастется, а код, соответствующий отказу от выбора, останется тем же. В результате практически весь код обработчика во втором варианте кода окажется вложенным в оператор if – а это может быть несколько страниц кода. В таком коде трудно разбираться. В первом варианте оператор if обладает небольшой областью действия, что позволяет легко разобраться с относящимся к нему кодом.
Можно было бы перенести строку
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser()
в обработчик события. В этом случае при каждом нажатии пункта меню "Файл/Открыть…" создавался бы новый объект-диалог. Такой код был бы работоспособен. Но создание диалога является относительно долгим процессом, требующим большого количества ресурсов операционной системы. Поэтому лучше создавать в приложении глобальную переменную, которой назначен диалог. Помимо прочего это позволяет в повторно открываемом диалоге оказываться в той же папке, где происходил последний выбор файла.
Перед вызовом диалога можно программно установить папку, в которой он будет открываться:
File folder=…; fileChooser.setCurrentDirectory(folder);
Диалог сохранения файла открывается аналогичным образом – showSaveDialog.
Практически всегда при использовании файловых диалогов требуется задавать фильтр, по которому просматриваются файлы. В подавляющем большинстве случаев требуется определенное расширение в имени файла. К сожалению, компонент JFileChooser до сих пор не поддерживает встроенной возможности настраивать фильтр – для этого требуется создание специального класса. Приведем пример простейшего такого класса:
package java_gui_example;
import java.io.*;
public class SimpleFileFilter extends javax.swing.filechooser.FileFilter {
String ext;
SimpleFileFilter(String ext){
this.ext=ext;
}
public boolean accept(File f){
if(f==null)
return false;
if(f.isDirectory()){
return true ;
}
else
return (f.getName().endsWith(ext));
}
/**
* Описание фильтра, возникающее в строке фильтра
* @see FileView#getName
*/
public String getDescription(){
return "Text files (.txt)";
}
}
Использование приведенного класса следующее: задается глобальная переменная
javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");
После чего она используется в обработчике события:
fileChooser.addChoosableFileFilter(fileFilter);
Данный оператор добавляет фильтр в выпадающий список возможных фильтров (масок) файлового диалога. Если добавляется уже существующий фильтр, операция добавления игнорируется.
По умолчанию показывается последний из добавленных фильтров. Если требуется показать другой фильтр, который уже был добавлен в список фильтров диалога, требуется вызвать оператор
fileChooser.setFileFilter(fileFilter);
Он делает добавленный фильтр текущим, то есть видимым при открытии диалога.
Кроме стандартных диалогов открытия и сохранения файлов имеется возможность вызова диалога с дополнительными программно задаваемыми элементами - с помощью метода showCustomDialog.
Также имеется возможность выбирать несколько файлов. Для этого до вызова диалога требуется задать разрешение на такой выбор:
fileChooser.setMultiSelectionEnabled(true);
Получение массива выбранных файлов после вызова диалога идет следующим образом:
java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null files.length > 0) {
String filenames = "";
for (int i=0; i<files.length; i++) {
filenames = filenames + "\n" + files[i].getPath();
}
}
Имеется возможность выбора папки (директории), а не файла. В этом случае следует задать режим, когда позволяется выбирать только папки
fileChooser.setFileSelectionMode(fileChooser.DIRECTORIES_ONLY);
либо и файлы, и папки
fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);
Возврат в обычный режим:
fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);
Для того, чтобы в выбранной папке просмотреть список файлов в папке, с которой связана переменная File folder, используется вызов вида
String[] filenames= folder.list(filter);
Получается массив строк с короткими именами файлов. Используется переменная filter, тип которой является классом, реализующим интерфейс java.io.FilenameFilter. О том, что такое интерфейсы, будет рассказано в отдельном разделе. Пример простейшего такого класса SimpleFilenameFilter:
package java_gui_example;
import java.io.*;
public class SimpleFilenameFilter implements FilenameFilter{
String ext;
public SimpleFilenameFilter(String ext) {
this.ext=ext;
}
public boolean accept(File dir,String fileName){
return ext==""||fileName.endsWith(ext);
}
}
Пример с показом файлов, содержащихся в выбранной папке, в компонент jTextArea1 (текстовая область) типа JTextArea, позволяющий показывать произвольное число строк:
String[] filenamesArray;
File folder=fileChooser.getSelectedFile();
SimpleFilenameFilter filter=new SimpleFilenameFilter("");
String filenames = "";
if(folder.isDirectory()){
filenamesArray=folder.list(filter);
for (int i=0; i<filenamesArray.length; i++) {
filenames = filenames + "\n" + filenamesArray[i];
};
jTextArea1.setText(filenames);
}
Аналогичный пример вывода выбранных в диалоге имен в режиме "мультиселект", позволяющем отмечать несколько файлов и/или папок:
java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null files.length > 0) {
String filenames = "";
for (int i=0; i<files.length; i++) {
filenames = filenames + "\n" + files[i].getPath();
};
jTextArea1.setText(filenames);
};
Стандартные классы Java, инкапсулирующие работу с данными (оболочечные классы для числовых данных, классы String и StringBuffer, массивы и т.д.), не обеспечивают поддержку чтения этих данных из файлов или запись их в файл. Вместо этого используется весьма гибкая и современная, но не очень простая технология использования потоков (Streams).
Поток представляет накапливающуюся последовательность данных, поступающих из какого-то источника. Порция данных может быть считана из потока, при этом она из потока изымается. В потоке действует принцип очереди – "первым вошел, первым вышел".
В качестве источника данных потока может быть использован как стационарный источник данных (файл, массив, строка), так и динамический – другой поток. При этом в ряде случаев выход одного потока может служить входом другого. Поток можно представить себе как трубу, через которую перекачиваются данные, причем часто в таких "трубах" происходит обработка данных. Например, поток шифрования шифрует данные, полученные на входе, и при считывании из потока передает их в таком виде на выход. А поток
Буферизуемые потоки имеют хранящийся в памяти промежуточный буфер, из которого считываются выходные данные потока. Наличие такого буфера позволяет повысить производительность операций ввода-вывода, а также осуществлять дополнительные операции – устанавливать метки (маркеры) для какого-либо элемента, находящегося в буфере потока и даже делать возврат считанных элементов в поток (в пределах буфера).
InputStream ("входной поток") инкапсулирует модель входных потоков, позволяющих считывать из них данные. OutputStream ("выходной поток") - модель выходных потоков, позволяющих записывать в них данные.
| Метод | Что делает |
|---|---|
int available() |
Текущее количество байт, доступных для чтения из потока. |
int read() |
Читает один байт из потока и возвращает его значение в виде целого, лежащего в диапазоне от 0 до 255. При достижении конца потока возвращает -1. |
int read(byte[] b)
|
Пытается прочесть b.length байт из потока в массив b. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
long |
Попытка пропускать (игнорировать) count байт из потока. count $$\le 0$$, пропуска байт нет. Возвращается реально пропущенное число байт. Если это значение $$\le 0$$, пропуска байт не было. |
boolean markSupported() |
Возвращает true в случае, когда поток поддерживает операции mark и reset, иначе – false. |
void mark(int limit) |
Ставит метку в текущей позиции начала потока. Используется для последующего вызова метода reset, с помощью которого считанные после установки метки данные возвращаются обратно в поток. Эту операцию поддерживают не все потоки. См. метод markSupported. |
void reset() |
Восстанавливает предшествующее состояние данных в начале потока, возвращая указатель начала потока на помеченный до того меткой элемент. То есть считанные после установки метки данные возвращаются обратно в поток. Попытка вызова при отсутствии метки или выходе ее за пределы лимита приводит к возбуждению исключения IOException. Эту операцию поддерживают не все потоки. См. методы markSupported и mark. |
void close() |
Закрытие потока. Последующие попытки чтения из этого потока приводят к возбуждению исключения IOException. |
Все методы класса InputStream, кроме markSupported и mark, возбуждают исключение IOException – оно возникает при ошибке чтения данных.
| Метод | Что делает |
|---|---|
void write(int b) |
Записывает один байт в поток. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу byte. Напомним, что в выражениях "короткие" целые типы автоматически преобразуются к типу int. |
void write(byte[] b)
|
Записывает в поток массив байт. Если заданы параметры offset и count, записывается не весь массив, а count байт начиная с индекса offset. |
void |
Форсирует вывод данных из выходного буфера и его очистку. Необходимость этой операции связана с тем, что в большинстве случаев данные уходят "во внешний мир" на запись не каждый раз после вызова write, а только после заполнения выходного буфера. Таким образом, если операции записи разделены паузой (большим интервалом времени), и требуется, чтобы уход данных из выходного буфера совершался своевременно, после последнего вызова оператора write, предшествующего паузе, надо вызывать оператор . |
void close() |
Закрытие потока. Последующие попытки записи в этот поток приводят к возбуждению исключения IOException. |
Все методы этого класса возбуждают IOException в случае ошибки записи.
Не все классы потоков являются потомками InputStream/OutputStream. Для чтения строк (в виде массива символов) используются потомки java.io. ("читатель"). В частности, для чтения из файла – класс FileReader. Аналогично, для записи строк используются классы - потомки java.io.Writer ("писатель"). В частности, для записи массива символов в файл – класс FileWriter.
Имеется еще один важный класс для работы с файлами, не входящий в иерархии InputStream/OutputStream и . Это класс RandomAccessFile ("файл с произвольным доступом"), предназначенный для чтения и записи данных в произвольном месте файла. Такой файл с точки зрения класса RandomAccessFile представляет массив байт, сохраненных на внешнем носителе. Класс RandomAccessFile не является абстрактным, поэтому можно создавать его экземпляры.
Все операции чтения и записи начинаются с позиции, задаваемой файловым указателем перед началом операции. После каждой такой операции файловый указатель сдвигается к концу файла на число позиций (байт), соответствующее типу считанных данных. В случае, когда во время записи файловый указатель выходит за конец файла, размер файла автоматически увеличивается.
| Метод | Что делает |
|---|---|
| Общие параметры файла | |
long getFilePointer() |
Возвращает значение файлового указателя - текущую позицию в файле считывающей/записывающей головки. Индексация начинается с нуля и дается в числе байт. |
long length() |
Длина файла (в байтах). |
void setLength(long newLength) |
Изменение длины файла – она устанавливается равной newLength. Если newLength меньше текущей длины, файл укорачивается путем отбрасывания его конца. При этом если файловый указатель находился в отбрасываемой части, он устанавливается в конец файла, иначе его позиция не меняется. Если newLength больше текущей длины, файл увеличивает размер путем добавления в конец нового пространства, содержимое которого не гарантируется. |
void close() |
Закрытие потока. Последующие попытки доступа к этому потоку приводят к возбуждению исключения IOException. |
| Побайтные операции установки позиции | |
void |
Установка файлового указателя в позицию . |
int skipBytes(int n) |
Пропуск n байт – передвижение считывающей/записывающей головки на n байт. Если $$n>0$$, то вперед, к концу файла. Если $$n\le 0$$, то позиция головки не меняется. Возвращается число реально пропущенных байт. Оно может быть меньше n – например, из-за достижения конца файла. |
| Побайтные операции чтения | |
int read() |
Читает один байт из потока и возвращает его значение в виде целого, лежащего в диапазоне от 0 до 255. При достижении конца потока возвращает -1. |
int read(byte[] b) |
Пытается прочесть b.length байт из потока в массив b. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
int read(byte[] b, int offset, int count) |
Пытается прочесть count байт из потока в массив b, записывая их начиная с позиции offset. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
void readFully(byte[] b) |
Считывает из файла b.length байт, начиная с текущей позиции файлового указателя, и заполняет весь буферный массив b. |
void readFully(byte[] b, int offset, int count) |
Считывает из файла в массив count байт, записывая их начиная с байта, имеющего позицию offset. |
| Побайтные операции записи | |
void write(int b) |
b. То же, что writeByte(b). |
void write(byte[] b) |
b, т.е. b.length байт. |
void write(byte[] b, int offset, int count) |
count байт массива b начиная с байта массива, имеющего индекс offset. |
| Чтение одиночных значений примитивного типа | |
boolean readBoolean() |
Считывает значение boolean |
byte readByte() |
Считывает значение byte |
short readShort() |
Считывает значение short |
int readInt() |
Считывает значение int |
long readLong() |
Считывает значение long |
int readUnsignedByte() |
Считывает значение типа "беззнаковый байт"(тип отсутствует в Java) и преобразует в значение типа int |
int readUnsignedShort() |
Считывает значение типа "беззнаковое короткое целое"(тип отсутствует в Java) и преобразует в значение типа int |
char readChar() |
Считывает значение char |
float readFloat() |
Считывает значение float |
double readDouble() |
Считывает значение double |
| Запись одиночных значений примитивного типа | |
void writeBoolean(boolean v) |
boolean |
void writeByte(int v) |
byte. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу byte. |
void writeShort(int v) |
short. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу short. |
void writeInt(int v) |
int |
void writeLong(long v) |
long |
void writeChar(int v) |
char. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу char. |
void writeFloat(float v) |
float |
void writeDouble(double v) |
double |
| Чтение отдельных строк | |
String readLine() |
Считывает из файла строку символов от текущей позиции файлового указателя до места переноса на новую строку (символ "\n" ) или конца файла. При этом старшие байты получившихся в строке символов UNICODE оказываются равными нулю, т.е. поддерживается только часть кодовой таблицы. Метод полезен для считывания текста, записанного в кодировке ANSI. |
String readUTF |
Считывает из файла строку символов в кодировке UTF-8 от текущей позиции файлового указателя. Число последующих считываемых байт строки в кодировке UTF-8 задается первыми двумя считанными байтами. |
| Запись отдельных строк | |
void writeBytes(String s) |
s как последовательности байт, соответствующих символам строки. При этом каждому символу соответствует один записываемый байт, так как у каждого символа UNICODE отбрасывается старший из двух байт ( записывается младший байт). Используется для записи символов в кодировке ANSI. См. также метод writeChars, в котором записываются оба байта. |
void writeChars(String s) |
s как последовательности байт, соответствующих символам строки. При этом каждому символу UNICODE соответствует два записываемых байта. |
void writeUTF(String s) |
|
Все методы класса RandomAccessFile, кроме getChannel(), возбуждают исключение IOException – оно возникает при ошибке записи или ошибке доступа к данным.
В конструкторе класса требуется указать два параметра. Первый – имя файла или
Например:
Рассмотрим примеры, иллюстрирующие работу с потоками.
Пример чтения текста из файла:
File file;
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();
javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");
private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
fileChooser.addChoosableFileFilter(fileFilter);
if(fileChooser.showOpenDialog(null)!=fileChooser.APPROVE_OPTION){
return;//Нажали Cancel
};
file = fileChooser.getSelectedFile();
try{
InputStream fileInpStream=new FileInputStream(file);
int size=fileInpStream.available();
fileInpStream.close();
char[] buff=new char[size];
Reader fileReadStream=new FileReader(file);
int count=fileReadStream.read(buff);
jTextArea1.setText(String.copyValueOf(buff));
javax.swing.JOptionPane.showMessageDialog(null,
"Прочитано "+ count+" байт");
fileReadStream.close();
} catch(Exception e){
javax.swing.JOptionPane.showMessageDialog(null,
"Ошибка чтения из файла \n"+file.getAbsolutePath());
}
}
Переменной fileInpStream, которая будет использована для работы потока FileInputStream, мы задаем тип InputStream. Это очень характерный прием при работе с потоками, позволяющий при необходимости заменять в дальнейшем входной поток с FileInputStream на любой другой без изменения последующего кода. После выбора имени текстового файла с помощью файлового диалога мы создаем файловый поток:
fileInpStream=new FileInputStream(file);
Функция fileInpStream.available() возвращает число байт, которые можно считать из файла. После ее использования поток fileInpStream нам больше не нужен, и мы его закрываем. Поток FileReader не поддерживает метод available(), поэтому нам пришлось использовать поток типа FileInputStream.
Массив buff используется в качестве буфера, куда мы считываем весь файл.
Если требуется читать файлы большого размера, используют буфер фиксированной длины и в цикле считывают данные из файла блоками, равными длине буфера, до тех пор, пока число считанных байт не окажется меньше размера буфера. Это означает, что мы дошли до конца файла. В таком случае выполнение цикла следует прекратить. При такой организации программы нет необходимости вызывать метод available() и использовать поток типа FileInputStream.
В операторе
Reader fileReadStream=new FileReader(file);
используется тип , а не FileReader, по той же причине, что до этого мы использовали InputStream, а не FileInputStream.
Построчное чтение из файла осуществляется аналогично, но содержимое блока try следует заменить на следующий код:
FileReader filReadStream=new FileReader(file);
BufferedReader bufferedIn=new BufferedReader(filReadStream);
String s="",tmpS="";
while((tmpS=bufferedIn.readLine())!=null)
s+=tmpS+"\n";
jTextArea1.setText(s);
bufferedIn.close();
Пример записи текста в файл очень похож на пример чтения, но гораздо проще, так как не требуется вводить промежуточные буферы и потоки:
private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
fileChooser.addChoosableFileFilter(fileFilter);
if(fileChooser.showSaveDialog(null)!=fileChooser.APPROVE_OPTION){
return;//Нажали Cancel
};
file = fileChooser.getSelectedFile();
try{
Writer filWriteStream=new FileWriter(file);
filWriteStream.write(jTextArea1.getText() );
filWriteStream.close();
} catch(Exception e){
javax.swing.JOptionPane.showMessageDialog(null,
"Ошибка записи в файл \n"+file.getAbsolutePath());
}
}
Иногда требуется использовать элементы, которые не являются ни числами, ни строками, но ведут себя как имена элементов и одновременно обладают порядковыми номерами. Например, названия месяцев или дней недели. В этих случаях используют перечисления. Для задания типа какого-либо перечисления следует написать зарезервированное слово (сокращение от
Тип-перечисление обязан быть глобальным – он может задаваться либо на уровне пакета, либо в каком-либо классе. Но его нельзя задавать внутри какого-либо метода. Элементы перечисления могут иметь любые имена, в том числе совпадающие в разных перечислениях или совпадающие с именами классов или их членов – каждое перечисление имеет свое собственное пространство имен. Доступ к элементу перечисления осуществляется с квалификацией именем типа-перечисления:
У каждого элемента перечисления имеется порядковый номер, соответствующий его положению в наборе - нумерация начинается с нуля. Поэтому первый элемент имеет номер 0, второй элемент – номер 1, и так далее. Имеется функция , возвращающая порядковый номер элемета в перечислении. Также имеется функция compareTo, позволяющая сравнивать два элемента перечисления - она возвращает разницу в их порядковых номерах.
Строковое представление значения можно получить с помощью функции name(). Преобразование из строки в значение типа "перечисление" осуществляется с помощью функции класса valueOf, в которую передается строковое представление значения.
Если требуется рассматривать элементы перечисления как массив, можно воспользоваться функцией values() – она возвращает массив элементов, к которым можно обращаться по индексу. Формат вызова функции такой: ИмяТипа.values()
Для примера зададим типы-перечисления Monthes ("месяцы") и
enum Monthes {jan,feb,mar,apr,may,jun,jul,aug,sept,oct,nov,dec};
enum Spring { march, apr, may };
Названия месяцев мы намеренно пишем со строчной буквы для того, чтобы было понятно, что это Monthes и для того, чтобы показать независимость их пространств имен. Объявление переменных типа "перечисление" делается так же, как для всех остальных типов, при этом переменные могут быть как неинициализированы, так и инициализированы при задании:
public Monthes m1 ,m2=Monthes.mar , m3; - при задании в классе общедоступных полей m1, m2 и m3,Spring spr1=Spring .apr , spr2; - при задании в методе локальной переменной или задании в классе поля spr1 с пакетным уровнем доступа.После чего возможны следующие операторы:
spr2=spr1;
spr1=Spring.may;
System.out.println("Результат сравнения="+spr2.compareTo(Spring.march));
После выполнения этих операторов в консольное окно будет выведен текст
Результат сравнения=1 ,
поскольку в переменной spr2 окажется значение порядковый номер которого на 1 больше, чем у значения с которым идет сравнение.
Пусть в переменной spr2 хранится значение . Порядковый номер значения, хранящегося в переменной, можно получить с помощью вызова spr2. Он возвратит число 2, так как may – третий элемент перечисления (сдвиг на 1 получается из-за того, что нумерация начинается с нуля).
Строковое представление значения, хранящегося в переменной spr2, можно получить с помощью вызова spr2.name(). Он возвратит строку "may" - имя типа в возвращаемое значение не входит.
Если переменная типа "перечисление" не инициализирована, в ней хранится значение null. Поэтому вызов
System.out.println("spr2="+spr2);
осуществленный до присваивания переменной spr2 значения возвратит строку
spr2=null
А вот попытки вызовов spr2. или spr2.name() приведут к возникновению ошибки (исключительной ситуации) с диагностикой
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Получение значения типа по номеру, хранящемуся в переменной i, осуществляется так:
spr1=Spring.values()[i];
Преобразование из строки в значение типа будет выглядеть так:
spr1=Spring.valueOf("march");
System.arraycopy. Быстрое заполнение массива одинаковыми значениями может осуществляться методом Arrays.fill - класс Arrays расположен в пакете java.util Поэлементное сравнение массивов следует выполнять с помощью метода Arrays.equals (сравнение на равенство содержимого массивов) либо Arrays.deepEquals (глубокое сравнение, то есть на равенство содержимого, а не ссылок – на произвольном уровне вложенности). Сортировка (упорядочение по значениям) массива производится методом Arrays.sort.String инкапсулирует действия со строками. Объект типа String – строка, состоящая из произвольного числа символов, от 0 до $$2*10^9$$. Литерные константы типа String представляют собой последовательности символов, заключенные в двойные кавычки. В классе Object имеется метод toString(), обеспечивающий строковое представление любого объекта.String являются неизменяемыми объектами – при каждом изменении содержимого строки создается новый объект-строка. Для того чтобы сделать работу с многочисленными присваиваниями более эффективной, используются классы StringBuffer и StringBuilder.java.awt .Graphics. Для того, чтобы результаты вывода не пропадали, в paint, вызываемый при отрисовке. А также обработчик события ComponentResized.Throwable. От Throwable наследуются классы Error ("Ошибка") и Exception ("Исключение"). Экземплярами класса Error являются непроверяемые исключительные ситуации, которые невозможно перехватить в блоках catch. Экземплярами класса Exception и его потомков являются проверяемые исключительные ситуации. Кроме одного потомка – класса RuntimeException (и его потомков).throws в заголовке метода указывать не надо. Если же в теле реализуемого метода используется вызов метода, который может возбуждать исключительную ситуацию, и это исключение не перехватывается, в заголовке реализуемого метода требуется указывать соответствующий тип возбуждаемого исключения.File обеспечивают работу с именами файлов и папок (проверка существования файла или папки с заданным именем, нахождение абсолютного пути по относительному и наоборот, проверка и установка JFileChooser (пакет javax.InputStream ("входной поток") инкапсулирует модель входных потоков, позволяющих считывать из них данные. OutputStream ("выходной поток") - модель выходных потоков, позволяющих записывать в них данные.Reader ("читатель"). В частности, для чтения из файла – класс FileReader. Аналогично, для записи строк используются классы- потомки Writer ("писатель"). В частности, для записи массива символов в файл – класс FileWriter.RandomAccessFile ("файл с произвольным доступом"), предназначенный для чтения и записи данных в произвольном месте файла. Такой файл с точки зрения класса RandomAccessFile представляет массив байт, сохраненных на внешнем носителе. Класс RandomAccessFile не является абстрактным, поэтому можно создавать его экземпляры.FileInputStream/FileOutputStream (потомков InputStream/OutputStream ). Использовать диалоги выбора файлов.RandomAccessFile. Использовать диалоги выбора файлов.JTextArea и считывания их из файла с помощью класса RandomAccessFile. Использовать диалоги выбора файлов. Проверить работу с русским языком при записи и чтении текста в различных кодировках (ANSI, UNICODE,UTF-8).JTable. Действия проводить с помощью массивов чисел типа double.Массив (array) – это упорядоченный набор одинаково устроенных ячеек, доступ к которым осуществляется по индексу. Например, если у массива имя a1, то a1[i] – имя ячейки этого массива, имеющей индекс i.
В Java массивы являются объектами, но особого рода – их объявление отличается от объявления других видов объектов. Переменная типа массив является ссылочной – в ней содержится адрес объекта, а не сам объект, как и для всех других
Тип ячейки массива называется базовым типом для массива.
Для задания массива, в отличие от объектов других типов, не требуется предварительно задавать класс, и иметь специальное имя для данного
Например, объявление
int[] a1;
задает переменную a1 типа массив. При этом размер массива (число ячеек в нем) заранее не задается и не является частью типа.
Для того, чтобы создать объект типа массив, следует воспользоваться зарезервированным словом new, после чего указать имя базового типа, а за ним в квадратных скобках число ячеек в создаваемом массиве:
a1=new int[10];
Можно совместить объявление типа переменной и
int[] a1=new int[10];
После null.
Ячейки в массиве имеют индексы, всегда начинающиеся с нуля. То есть первая ячейка имеет номер 0, вторая – номер 1, и так далее. Если n, то последняя ячейка имеет индекс n-1. Такая своеобразная нумерация принята в языках C и C++, и язык Java унаследовал эту не очень привлекательную особенность, часто приводящую к ошибкам при организации циклов.
Длина массива хранится в поле length, которое доступно только по чтению – изменять его путем присваивания нового значения нельзя.
Пример работы с массивом:
int[] a=new int[100];
for(int i=0;i<a.length;i++){
a[i]=i+1;
};
Если у нас имеется переменная типа массив, и ей сопоставлен массив заданной длины, в любой момент этой переменной можно сопоставить новый массив. Например,
a1=new int[20];
При этом прежний объект-массив, находящийся в динамической области памяти, будет утерян и превратится в мусор.
Переменные типа массив можно присваивать друг другу. Например, если мы задали переменную
int[] a2;
то сначала в ней хранится значение null (ссылка направлена "в никуда"):
(рис 7.1) Массив с ячейками типа intПрисваивание
a2=a1;
приведет к тому, что ссылочные переменные a1 и a2 будут ссылаться на один и тот же массив, расположенный в динамической области памяти.
(рис 7.2) Массив с ячейками типа intТо есть присваивание переменных типа массив приводит к тому, что имена переменных становятся синонимами одного и того же массива – копируется адрес массива. А вовсе не приводит к копированию элементов из одного массива в другой, как это происходит в некоторых других языках программирования.
В качестве элементов массивов могут выступать объекты. В этом случае доступ к полям и методам этих объектов производится через имя ячейки массива, после которого через точку указывается имя поля или метода. Например, если у нас имеется класс Circle ("окружность"), у которого имеются поля x, y и r, а также методы show() и hide(), то массив circles из 10 объектов такого типа может быть задан и инициализирован, например, так
int n=10;
Circle[] circles=new Circle[n];
for(int i=0;i<n;i++){
circles[i]=new Circle();
circles[i].x=40*i;
circles[i].y= circles[i].x/2;
circles[i].r=50;
circles[i].show();
};
В такого рода программах для повышения читаемости часто применяется использование вспомогательной ссылки, позволяющей избежать многократного обращения по индексу. В нашем случае мы будем использовать в этих целях переменную circle. На скорости работы программы это почти не сказывается (хотя и может чуть повысить быстродействие), но делает код более читаемым:
int n=10;
Circle[] circles=new Circle[n];
Circle circle;
for(int i=0;i<n;i++){
circle=new Circle();
circle.x=40*i;
circle.y= circles[i].x/2;
circle.r=50;
circle.show();
circles[i]= circle;
};
С помощью переменной circle мы инициализируем создаваемые объекты и показываем их на экране, после чего присваиваем ссылку на них ячейкам массива.
int[][] a=new int[10][20];
Будет задана ячейка типа "int[], а для ячеек по второму индексу int.
Рассмотрим работу с двумерными массивами на примере заполнения двумерного массива случайными числами:
int m=10;//10 строк
int n=20;//20 столбцов
int[][] a=new int[m][n];
for(int i=0;i<m;i++){ //цикл по строкам
for(int j=0;j<n;j++){ //цикл по столбцам
a[i][j]=(int)(100*Math.random());
System.out.print(a[i][j]+" ");
};
System.out.println();//перевод на новую строку после вывода строки матрицы
};
Многомерные массивы задаются аналогично двумерным – только указывается необходимое количество прямоугольных скобок. Следует отметить, что массивы размерности больше 3 используют крайне редко.
Обычно в двумерных и многомерных массивах задают одинаковый размер всех массивов, связанных с ячейками по какому-либо индексу. Такие массивы называют регулярными. В Java, в отличие от большинства других языков программирования, можно задавать массивы с разным размером массивов, связанных с ячейками по какому-либо индексу. Такие "непрямоугольные" массивы называют иррегулярными. Обычно их используют для экономии памяти. При работе с иррегулярными массивами следует быть особенно аккуратными, так как разный размер "вложенных" массивов часто приводит к ошибкам при реализации алгоритмов.
Пример задания иррегулярного двумерного массива треугольной формы:
int n=9;
int[][] a=new int[n][];
for(int i=0;i<a.length;i++){ //цикл по строкам
a[i]=new int[i+1]; //число элементов в строке равно i+1
for(int j=0;j<a[i].length;j++){ //цикл по столбцам
a[i][j]=100*i+j;
System.out.print(a[i][j]+" ");
};
System.out.println();//перевод на новую строку после вывода строки матрицы
};
После
int[] a=new int[4]; a[0]=2; a[1]=0; a[2]=0; a[3]=6;
Но гораздо удобнее следующий вариант синтаксиса:
int[] a=new int[] {2,0,0,6};
При этом приходится задавать массив без указания его размера непосредственно с помощью указания значений в фигурных скобках:
В правой части оператора присваивания стоит так называемый анонимный массив – у него нет имени. Такие массивы обычно используют для инициализации, а также при написании кода для различного рода проверок.
Если мы хотим присвоить новые значения, приходится либо присваивать поэлементно, либо создавать новый объект:
a=new int[] {2,0,0,6};
При инициализации двумерных и многомерных массивов используют вложенные массивы, задаваемые с помощью фигурных скобок. Например, фрагмент кода
int[][] b= new int[][]
{
{2,0,0,0}, //это b[0]
{2,0,0,1}, //это b[1]
{2,0,0,2}, //это b[2]
{1,0,0,0}, //это b[3]
{2,0,0,0}, //это b[4]
{3,0,0,0}, //это b[5]
};
приведет к заданию целочисленного двумерного массива b, состоящего из 6 строк и 4 столбцов, т.е. int[6][4]. Таким образом можно задавать как регулярные, так и иррегулярные массивы. Но следует помнить, что в таком варианте синтаксиса проверки правильности размера массива по индексам не делается, что может привести к ошибкам. Например, следующий код при компиляции не выдаст ошибки, а будет создан иррегулярный массив:
int[][] b= new int[][]
{
{2,0,0,0}, //это b[0]
{2,0,0,1}, //это b[1]
{2,0,0,2}, //это b[2]
{1,0,0,0}, //это b[3]
{2,0,0,0}, //это b[4]
{3,0,0}, //это b[5] – массив из трех элементов
};
Из объектов-массивов можно вызывать метод , позволяющий создавать копию (клон) массива:
a=new int[] {2,0,0,6};
int[] a1=a.clone();
Напомним, что присваивание
int[] b=a;
не приведет к копированию массива – просто переменная b станет ссылаться на тот же объект-массив. Копирование массивов можно осуществлять в цикле, но гораздо быстрее использовать метод System.arraycopy.
int[] b=new int[a.length+10]; System.arraycopy(a,index1a,b, index1b,count);
Из a в b копируется count элементов начиная с индекса index1a в массиве a. Они размещаются в массиве b начиная с индекса index1b. Содержимое остальных элементов b не меняется. Для использования метода требуется, чтобы массив b существовал и имел необходимую длину - при выходе за границы массивов возбуждается исключительная ситуация.
Быстрое заполнение массива одинаковыми значениями может осуществляться методом Arrays.fill(массив, значение). Класс Arrays расположен в пакете java.util.
Поэлементное Arrays.equals(a,a1). Заметим, что у любого массива имеется метод equals, унаследованный от класса Object и позволяющий сравнивать массивы. Но, к сожалению, метод не переопределен, и сравнение идет по адресам объектов, а не по содержимому. Поэтому a.equals(a1) это то же самое, что a==a1. Оба сравнения вернут false, так как адреса объектов, на которые ссылаются переменные a и a1, различаются. Напротив, сравнения a.equals(a3) и a==a3 вернут true, так как a и a3 ссылаются на один и тот же объект-массив.
Сортировка (упорядочение по значениям) массива a производится методами Arrays.sort(a) и Arrays.sort(a,index1,index2). Первый из них упорядочивает в порядке возрастания весь массив, второй – часть элементов (от индекса index1 до индекса index2 ). Имеются и более сложные методы сортировки. Элементы массива должны быть сравниваемы (поддерживать операцию сравнения).
Arrays.deepEquals(a1,a2) – сравнение на равенство содержимого a1 и a2 путем глубокого сравнения (на равенство содержимого, а не ссылок – на произвольном уровне вложенности).
Также в классе Arrays содержится большое число других полезных методов.
В Java получили широкое использование коллекции (Collections) – "умные" массивы с динамически изменяемой длиной, поддерживающие ряд важных дополнительных операций по сравнению с массивами. Базовым для иерархии коллекций является класс java.util.AbstractCollection. (В общем случае класс коллекции не обязан быть потомком AbstractCollection – он может является любым классом, реализующим интерфейс Collection ). Основные классы и интерфейсы коллекций:
Set, SortedSet ; классы HashSet, TreeSet, EnumSet, LinkedHashSet — множества (неупорядоченные или некоторым образом упорядоченные наборы неповторяющихся элементов);java.util.List ; классы java.awt .List, ArrayList , LinkedList, Vector — списки (упорядоченные наборы элементов, причем элементы могут повторяться в разных местах списка);Map, SortedMap ; классы HashMap, HashTable , ConcurrentHashMap, TreeMap, EnumMap, Properties — таблицы (списки пар "имя-значение").Доступ к элементам коллекции в общем случае не может осуществляться по индексу, так как не все коллекции поддерживают индексацию элементов. Эту функцию осуществляют с помощью специального объекта – ). У каждой коллекции collection имеется свой
Iterator iter = collection.iterator()
У итераторов имеются следующие три метода:
boolean hasNext() - дает информацию, имеется ли в коллекции следующий объект.Object next() – возвращает ссылку на следующий объект коллекции.void remove() – удаляет из коллекции текущий объект, то есть тот, ссылка на который была получена последним вызовом next().Пример преобразования массива в коллекцию и цикл с доступом к элементам этой коллекции, осуществляемый с помощью
java.util.List components= java.util.Arrays.asList(this.getComponents());
for (Iterator iter = components.iterator();iter.hasNext();) {
Object elem = (Object) iter.next();
javax.swing.JOptionPane.showMessageDialog(null,"Компонент: "+
elem.toString());
}
| Имя метода | Действие |
|---|---|
boolean add(Object obj) |
Добавление объекта в коллекцию (в конец списка). Возвращает true в случае успешного добавления - изменения коллекции. Коллекция может не позволить добавление элементов несовместимого типа или не подходящих по какому-либо другому признаку. |
boolean addAll(Collection c) |
Добавление в коллекцию всех объектов из другой коллекции. Возвращает true в случае успешного добавления, то есть если добавлен хотя бы один элемент. |
void clear() |
Очистка коллекции - удаление из нее ссылок на все входящие в коллекцию объекты. При этом те объекты, на которые имеются ссылки у других элементов программы, не удаляются из памяти. |
boolean contains(Object obj) |
Возвращает true в случае, если коллекция содержит объект obj. Проверка осуществляется с помощью поочередного вызова метода obj.equals(e) для элементов e, входящих в коллекцию. |
boolean containsAll(Collection c) |
Возвращает true в случае, если коллекция содержит все элементы коллекции c. |
boolean |
Возвращает true в случае, если коллекция пуста, то есть не содержит ни одного элемента. |
|
Возвращает ссылку на next() дает ссылку на начальный элемент коллекции. |
boolean remove(Object obj) |
Удаляет из коллекции первое встретившееся вхождение объекта obj. Поиск и удаление осуществляется с помощью true в случае, если удаление удалось, то есть если коллекция изменилась. |
boolean removeAll(Collection c) |
Удаляет из коллекции все элементы коллекции c. Возвращает true в случае, если удаление удалось, то есть если коллекция изменилась. |
boolean retainAll(Collection c) |
Оставляет в коллекции только те из входящих в нее элементов, которые входят в коллекцию c. |
int size() |
Возвращает число элементов в коллекции. |
Object[] toArray() |
Возвращает массив ссылок на объекты, содержащиеся в коллекции. То есть преобразует коллекцию в массив. |
T[] toArray(T[n] a) |
Возвращает массив элементов типа T, полученных в результате преобразования элементов, содержащихся в коллекции. То есть преобразует коллекцию в массив. Если число элементов коллекции не превышает размер n массива a, размещение данных производится в существующих ячейках памяти, отведенных под массив. Если превышает n – в памяти динамически создается и заполняется новый набор ячеек, и их число делается равным числу элементов коллекции. После чего переменная a начинает ссылаться на новый набор ячеек. |
String toString() |
Метод переопределен – он возвращает строку со списком элементов коллекции. В списке выводятся заключенные в квадратные скобки строковые представления элементов, разделяемые комбинацией "," – запятая с пробелом после нее. |
Самыми распространенными вариантами коллекций являются списки ( Lists ). Они во многом похожи на массивы, но отличаются от массивов тем, что в списках основными операциями являются добавление и удаление элементов. А не доступ к элементам по индексу, как в массивах.
В классе List имеются методы коллекции, а также ряд дополнительных методов:
list.get(i) – получение ссылки на элемент списка list по индексу i.list.indexOf (obj) - получение индекса элемента obj в списке list. Возвращает -1 если объект не найден.list.listIterator() – получение ссылки на ListIterator, обладающего дополнительными методами по сравнению с Iterator .list.listIterator(i) – то же с позиционированием i.list.remove(i) – удаление из списка элемента с индексом i.list.set(i,obj) – замена в списке элемента с индексом i на объект obj.list.subList (i1,i2) – возвращает ссылку на подсписок, состоящий из элементов списка с индексами от i1 до i2.Кроме них в классе List имеются и многие другие полезные методы.
Ряд полезных методов для работы с коллекциями содержится в классе Collections:
Collections.addAll(c,e1,e2,…,eN) - добавление в коллекцию c произвольного числа элементов e1,e2,…,eN.Collections.frequency (c,obj) – возвращает число вхождений элемента obj в коллекцию c.Collections.reverse(list) – обращает порядок следования элементов в списке list (первые становятся последними и наоборот).Collections.sort(list) – сортирует список в порядке возрастания элементов. Сравнение идет вызовом метода e1.compareTo(e2) для очередных элементов списка e1 и e2.Кроме них в классе Collections имеются и многие другие полезные методы.
В классе Arrays имеется метод
Arrays.asList(a) – возвращает ссылку на список элементов типа T, являющийся оболочкой над массивом T[] a. При этом и массив, и список содержат одни и те же элементы, и изменение элемента списка приводит к изменению элемента массива, и наоборот.Класс String инкапсулирует действия со строками. Объект типа String - строка, состоящая из произвольного числа символов, от 0 до $$2*10^9$$. Литерные константы типа String представляют собой последовательности символов, заключенные в двойные кавычки: "A", "
Это так называемые "длинные" строки. Внутри литерной строковой константы не разрешается использовать ряд символов - вместо них применяются управляющие последовательности.
Внутри строки разрешается использовать переносы на новую строку. Но литерные константы с такими переносами запрещены, и надо ставить "\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 могут быть использованы значения "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, и преобразованными к нижнему регистру (строчным буквам). Имеется вариант метода, делающего такое преобразование с учетом конкретной кодировки ( 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". Совершенно так же выполняется
Еще более странный результат получится при присваивании
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, ) с помощью метода :
Byte.decode ( строка ) , и т.п.Также полезны методы для анализа отдельных символов:
Character.isDigit ( символ ) – булевская функция, проверяющая, является ли символ цифрой.Character.isLetter ( символ ) – булевская функция, проверяющая, является ли символ буквой.Character.isLetterOrDigit ( символ ) – булевская функция, проверяющая, является ли символ буквой или цифрой.Character.isLowerCase ( символ ) – булевская функция, проверяющая, является ли символ символом в нижнем регистре.Character.isUpperCase ( символ ) – булевская функция, проверяющая, является ли символ символом в верхнем регистре.Character.isWhitespace ( символ ) – булевская функция, проверяющая, является ли символ "пробелом в широком смысле" – пробелом, символом табуляции, перехода на новую строку и т.д.Для того чтобы сделать работу с многочисленными присваиваниями более эффективной, используются классы StringBuffer и StringBuilder. Они особенно удобны в тех случаях, когда требуется проводить изменения внутри одной и той же строки (убирать или вставлять символы, менять их местами, заменять одни на другие). Изменение значений переменных этого класса не приводит к созданию мусора, но несколько медленнее, чем при работе с переменными типа String. Класс StringBuffer рекомендуется использовать в тех случаях, когда используются потоки ( threads ) – он, в отличие от классов String и StringBuilder, обеспечивает синхронизацию строк. Класс StringBuilder, введенный начиная с
К сожалению, совместимости по присваиванию между переменными этих классов нет, как нет и возможности преобразования этих типов. Но в классах 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);
Буферизуемые и обычные строки можно сравнивать на совпадение содержания: s1.contentEquals(sb) – булевская функция, возвращающая true в случае, когда строка s1 содержит такую же последовательность символов, как и строка sb.
Вывод графики осуществляется с помощью объектов типа java.. Для них определен ряд методов, описанных в следующей далее таблице.
Подразумевается, что 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) ;
|
Вывод многоугольника по массиву точек, 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 и другие перегруженные варианты метода |
Вывод изображения. |
| Рисование заполненных фигур | |
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)
|
Вывод многоугольника, заполненного текущим цветом. |
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)
|
Установка новых границ области вывода. Вне этой области при выводе графических примитивов они усекаются (не выводятся). |
clipRect(x,y,w,h) |
Сужение области вывода. |
Rectangle getClipBounds()
|
Возвращает параметры прямоугольника, в который вписана область вывода. |
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<=100;i++){
FiguresUtil.moveFigureBy(figure,dx,dy);
update(g);
};
При работе со статическими изображениями изложенных алгоритмов вполне достаточно. Однако при использовании движущихся элементов во многих
При работе программы выполнение операторов обычно идет в рамках "основного ствола" - в случае, когда все идет как надо. Но время от времени возникают исключительные ситуации ( исключения - exceptions), приводящие к ответвлению от основного ствола: деление на 0, отсутствие места на диске или попытка писать на защищенную для записи дискету, ввод с клавиатуры ошибочного символа (например, буквы вместо цифры). В отличие от катастрофических ситуаций (ошибок) такие ситуации в большинстве случаев могут быть учтены в программе, и, в частности, они не должны приводить к аварийному завершению программы.
В языках программирования предыдущих поколений для решения указанных проблем приходилось использовать огромное число проверок на допустимость присваиваний и математических операций. Мало того, что эти проверки резко замедляли работу программы - не было гарантии, что они достаточны, и что во время работы программы не возникнет "вылет" из-за возникновения непредусмотренной ситуации.
В Java, как и в других современных языках программирования, для таких целей предусмотрено специальное средство — обработка исключительных ситуаций. При этом используется так называемый защищенный блок программного кода try ("попытаться"), после которого следует необязательные блоки перехвата исключений catch, за которыми идет необязательный блок очистки ресурсов finally.
Про наступившую исключительную ситуацию говорят, что она возникает, либо – что она возбуждается. В английском языке для этого используется слово throw – "бросить". Поэтому иногда в переводной литературе используют дословный перевод "бросается исключительная ситуация".
Общий случай использования защищенного блока программного кода и перехвата исключительных ситуаций выглядит так:
try{
операторы0;
}
catch (ТипИсключения1 переменная1){
операторы1;
}
catch (ТипИсключения2 переменная2){
операторы2;
}
catch (ТипИсключенияN переменнаяN){
операторыN;
}
finally{
операторы;
}
Отметим, что при задании блоков try-catch-finally после фигурных скобок точку с запятой ";" можно не ставить, как и всегда в случае использования фигурных скобок. Но можно и ставить - по усмотрению программиста.
Если исключительных ситуаций не было, операторы0 в блоке try выполняются в обычном порядке, после чего выполняются операторы в блоке finally. Если же возникла исключительная ситуация в блоке try, выполнение блока прерывается, и идет перехват исключений в блоках catch ("перехватить"). В качестве параметра оператора catch задается ссылочная переменная, имеющая тип той исключительной ситуации, которую должен e (по первой букве от exception). Если catch не делается.
После проверок и, возможно, перехвата исключения в блоках catch выполняются операторы блока finally. Его обычно используют для высвобождения ресурсов, и поэтому часто называют блоком "очистки ресурсов". Специальных операторов или зарезервированных конструкций для обработки в блоке finally нет. Отличие кода внутри блока finally от кода, стоящего после оператора try…finally, возникает только при наличии внутри блоков try или catch операторов break, continue, return или System.exit, то есть операторов, прерывающих работу блока программного кода. В этом случае независимо от их срабатывания или несрабатывания сначала происходит выполнение операторов блока finally, и только потом происходит переход в другое место программы в соответствии с оператором прерывания.
Пример обработки исключений:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(ArithmeticException e){
System.out.println("Деление на ноль");
} catch(NumberFormatException e){
System.out.println("Корень из отрицательного числа!");
}
};
Исключительные ситуации в Java являются объектами. Их типы являются классами-потомками Throwable (от throw able – "способный возбудить исключительную ситуацию"). От Throwable наследуются классы Error ("Ошибка") и Exception ("Исключение"). Экземплярами класса Error являются непроверяемые исключительные ситуации, которые невозможно перехватить в блоках catch. Такие исключительные ситуации представляют катастрофические ошибки, после которых невозможна нормальная работа приложения. Экземплярами класса Exception и его потомков являются проверяемые исключительные ситуации. Кроме одного потомка – класса RuntimeException (и его потомков). Имя этого класса переводится как "Исключительные ситуации времени выполнения".
Классы исключительных ситуаций либо предопределены в стандартных пакетах (существуют исключительные ситуации ArithmeticException для арифметических операций в пакете java.lang, IOException в пакете java.io, и так далее), либо описываются пользователем как потомки класса Exception или его потомков.
В Java типы-исключения принято именовать, оканчивая имя класса на "Exception" ("Исключение") для "Error" ("Ошибка") для непроверяемых.
По правилу catch имеет большое значение: обработчик исключения более общего типа следует писать всегда после обработчика для его типа-потомка, иначе обработчик потомка никогда не будет вызван.
В приведенном выше примере вместо NumberFormatException можно поставить Exception, так как других типов исключений кроме NumberFormatException сюда доходить не может. В этом случае метод выглядит так:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(ArithmeticException e){
System.out.println("Деление на ноль");
} catch(Exception e){
System.out.println("Корень из отрицательного числа!");
}
};
Но если бы мы попробовали таким же образом заменить catch, то блок для исключений типа Exception всегда перехватывал бы управление, и обработчик для NumberFormatException никогда бы не срабатывал. Пример такого неправильно написанного кода:
void myETest(String s,double y){
double x, z;
try{
x=Double.parseDouble(s);
z=Math.sqrt(x/y);
} catch(Exception e){
System.out.println("Деление на ноль");
} catch(NumberFormatException e){
System.out.println("Корень из отрицательного числа!");
}
};
В таких случаях среда разработки NetBeans выдаст сообщение вида "exception java.lang.NumberFormatException has already been caught" – "исключение java.lang.NumberFormatException уже было перехвачено".
Для того чтобы задать собственный тип исключительной ситуации, требуется задать соответствующий класс. Он должен быть наследником от какого-либо класса исключительной ситуации.
Например, зададим
class WrongPasswordException extends Exception {
WrongPasswordException(){ // конструктор
System.out.println("Wrong password!");
}
}
Создание объекта-исключения может проводиться в произвольном месте программы обычным образом, как для всех объектов, при этом возбуждения исключения не происходит.
Программное возбуждение исключительной ситуации производится с помощью оператора throw, после которого указывается оператор создания объекта-исключения:
throw new ТипИсключения();
Например,
throw new WrongPasswordException();
Если после частичной обработки требуется повторно возбудить исключительную ситуацию e, используется вызов
throw e;
Для finally, если он есть, и всплывание продолжается – происходит выход из текущего метода в метод более высокого уровня. Соответственно, исключение начинает обрабатываться на уровне этого метода. Если оно не перехватывается, происходит выход на еще более высокий уровень, и так далее.
Если в методе исключение данного типа перехватывается, всплывание прекращается. Если же ни на каком уровне исключение не перехвачено – оно обрабатывается исполняющей средой. При этом выполняются действия, предусмотренные в конструкторе исключения, а затем система выводит служебную информацию о том, где и какого типа исключение возникло.
Исключительная ситуация – это особая, экстремальная ситуация, не планируемая заранее. Не следует использовать исключения в качестве конструкций, на которых основаны часто повторяющиеся в программе действия.
Задание: усовершенствовать класс WrongPasswordException таким образом, чтобы сообщение об ошибке появлялось в виде диалогового окна.
Формат
Модификаторы Тип Имя(список параметров)
throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN
{
Тело функции
}
Аналогичным образом объявляется конструктор, который может возбуждать проверяемые исключительные ситуации:
Модификаторы ИмяКласса(список параметров)
throws ТипИсключения1, ТипИсключения2,…, ТипИсключенияN
{
Тело конструктора
}
Слово throws означает "возбуждает исключительную ситуацию" (дословно – "бросает").
throws в заголовке метода указывать не надо.
Если в теле реализуемого метода используется вызов метода, который может возбуждать исключительную ситуацию, и это исключение не перехватывается, в заголовке реализуемого метода требуется указывать соответствующий тип возбуждаемого исключения. Если же это исключение порождается внутри защищенного блока программного кода, и в каком-либо блоке catch перехватывается этот
Как мы уже знаем, в throw, возбуждающий исключительную ситуацию. В этом случае если объект-исключение не перехвачен, в заголовке метода требуется указывать соответствующий тип возбуждаемого исключения. В частности, оператор throw может быть использован для порождения исключения другого типа после обработки перехваченного исключения в блоке catch.
Если в
Пример: проверка пароля, введенного пользователем.
class CheckPasswordDemo{
private String password="";
public String getPassword(){
return password;
};
public void setPassword(){
...//реализация метода
};
public void checkPassword(String pass)
throws WrongPasswordException {
if(!pass.equals(password))
throw new WrongPasswordException();
};
}
При вызове метода checkPassword в случае неправильного пароля, переданного в качестве параметра, возбуждается исключительная ситуация. Следует обратить внимание, что сравнение pass!=password всегда будет давать true, так как строки сравниваются как объекты. То есть при сравнении "==" проверяется идентичность адресов в памяти, а не содержание строк.
Еще один момент, на котором следует остановиться: не используйте else в операторе if! Возбуждение исключения выполняется намного дольше, потребляет много ресурсов и при неудачном использовании только ухудшает программу. Например, в нашем случае имело бы смысл при неправильном вводе пароля предусмотреть возможность еще двух попыток ввода в обычном режиме – и только после третьей неудачной попытки возбуждать исключение.
Концепция работы с файлами в Java включает две составляющие:
File.Обеспечивает работу с именами файлов (проверка существования файла или папки с заданным именем, нахождение абсолютного пути по относительному и наоборот, проверка и установка
Обеспечивает работу не только с файлами, но и с памятью, а также различными устройствами ввода-вывода.
Объекты типа File могут рассматриваться как абстракции, инкапсулирующие работу с именами файлов и папок. При этом папка рассматривается как разновидность файла, обладающая особыми атрибутами.
Создание объекта типа File осуществляется с помощью конструкторов, имеющих следующие варианты:
При этом имена могут быть как короткими (локальными), без указания пути к файлу или папке, так и длинными (абсолютными), с указанием пути. В приведенной далее таблице файлы (папки) ищутся по имени в соответствии с правилами поиска файлов в операционной системе. Для платформы Windows® вместо символа "\" в строках, соответствующих путям, должна использоваться последовательность "\\".
Важнейшие файловые операции, инкапсулированные классом File:
| Поле или метод | Что содержит или делает |
|---|---|
| Переменные класса | |
String pathSeparator |
Содержит строку с символом разделителя пути в операционной системе. Это "/" в Unix-подобных системах и "\" в Windows®. |
char pathSeparatorChar |
Содержит символ разделителя пути в операционной системе. Это '/' в Unix-подобных системах и '\' в Windows®. |
String separator |
Содержит строку с символом разделителя между именами файлов и файловых масок в операционной системе. |
char separatorChar |
Содержит символ разделителя между именами файлов и файловых масок в операционной системе. |
| Проверка параметров файла или папки | |
boolean exists() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует. Иначе false. |
long length() |
Возвращает длину файла в байтах в случае, когда файл с заданным в конструкторе именем существует и не является папкой. Иначе 0L. |
boolean canRead() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует и доступен по чтению. Иначе false. (В Unix-подобных системах существуют файлы, доступные только по записи). Может возбуждать SecurityException. |
boolean setReadOnly() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует, и ему удалось установить статус "доступен только по чтению". Иначе false. |
boolean canWrite() |
Возвращает true в случае, когда файл (или папка) с заданным в конструкторе именем существует и доступен по записи. Иначе false. (В операционных системах существуют файлы, доступные только по чтению). Может возбуждать SecurityException. |
boolean isDirectory() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является папкой. Иначе false. |
boolean isFile() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является файлом. Иначе false. |
boolean isHidden() |
Возвращает true в случае, когда файл или папка с заданным в конструкторе именем существует и является скрытым. Иначе false. В Unix-образных системах скрытыми являются файлы, имена которых начинаются с точки. В Windows® – те, которые имеют атрибут "hidden" ("скрытый"). |
long lastModified() |
Возвращает время последней модификации файла, если он существует и доступен по чтению. Иначе 0L. Время отсчитывается в миллисекундах, прошедших с 0 часов 1 января 1970 года (по Гринвичу). |
boolean setLastModified(long time) |
Устанавливает время последней модификации файла. Возвращает true, если он существует и доступен по записи. Иначе false. Время отсчитывается в миллисекундах, прошедших с 0 часов 1 января 1970 года (по Гринвичу). |
| Путь и имя файла (папки) | |
String getName() |
Возвращает короткое имя файла или папки. |
String getParent() |
Возвращает абсолютное имя родительской папки – то есть папки, в которой находится файл (или папка), соответствующий файловому объекту. |
String getAbsolutePath() |
Возвращает абсолютный путь к файлу или папке, включая имя файла. При этом если в имени файла в конструкторе была задана |
String getCanonicalPath() |
Возвращает абсолютный путь к файлу или папке, включая имя файла. При этом если в имени файла в конструкторе была задана IOException, если канонический путь не может быть построен. |
int compareTo(File f) |
Сравнение имен файлов (папок), сопоставляемых текущему файловому объекту и объекту f. Возвращает 0 в случае, когда абсолютные имена файлов (папок) совпадают. Иначе возвращает число, зависящее от разницы в длинах имен и кодов составляющих их символов. Сравнение зависимо от операционной системы – в Unix-образных системах регистр символов имеет значение, в Windows® – не имеет. Соответствие понимается абстрактно на уровне имен и путей – самих файлов может не существовать. |
boolean isAbsolute() |
Возвращает true в случае, когда адресация к имени файла (папки) текущего файлового объекта является абсолютной. Хотя может содержать элементы относительной адресации, то есть не быть канонической. |
boolean equals(Object obj) |
Возвращает true тогда и только тогда, когда текущий объект и параметр obj соответствуют одному и тому же файлу (папке) . С учетом правил о путях и регистрах символов, задаваемых операционной системой. Соответствие понимается абстрактно на уровне имен и путей – самих файлов может не существовать. |
| Создание/уничтожение/переименование файлов и папок | |
boolean createNewFile() |
Попытка создания файла или папки по имени, которое было задано в конструкторе объекта. В случае успеха возвращается true, иначе false. Возбуждает IOException, если файл не может быть создан (например, уже существует). |
File createTempFile(String
|
Метод класса. Обеспечивает создание пустого файла (или папки), задаваемого коротким именем в папке операционной системы, предназначенной для временных файлов. Возвращает ссылку на объект. Префикс должен быть не менее 3 символов. Возбуждает IOException, если файл не может быть создан (например, уже существует). |
boolean mkdir() |
Попытка создания папки по имени, которое было задано в конструкторе объекта. Возвращает true в случае успешного создания и false в других случаях. |
boolean mkdirs() |
Попытка создания папки по имени, которое было задано в конструкторе объекта, причем заодно создаются все папки, заданные в пути, если они не существовали. Возвращает true в случае успешного создания и false в других случаях. |
boolean delete() |
Попытка удаления файла или папки по имени, которое было задано в конструкторе объекта. Возвращает true в случае успешного удаления и false в других случаях. |
boolean renameTo(File dest) |
Попытка переименования файла или папки с имени, которое было задано в конструкторе объекта, на новое, задаваемое параметром dest. Возвращает true в случае успешного переименования и false в других случаях. |
| Создание нового файлового объекта с помощью имеющегося | |
File getAbsoluteFile() |
Создание нового файлового объекта по абсолютному пути, соответствующему текущему файловому объекту. |
File getCanonicalFile() |
Создание нового файлового объекта по каноническому пути, соответствующему текущему файловому объекту. Возбуждает IOException, если канонический путь не может быть построен. |
File getParentFile() |
Создание нового файлового объекта по абсолютному пути, соответствующему родительской папке для текущего файлового объекта. |
| Списки папок и файлов | |
String[] list()
|
Возвращает массив строк (список) коротких имен находящихся в папке файлов и папок. Имена элементов, находящихся во null. При наличии фильтра возвращаются только те имена, которые соответствуют маске фильтра. |
File[] listFiles()
|
Возвращает массив файловых объектов, соответствующих находящимся в папке файлов и папок. Элементы, находящиеся во null. При наличии фильтра возвращаются объекты только для тех имен, которые соответствуют маске фильтра. |
File[] listRoots() |
Возвращает массив файловых объектов, соответствующих возможным на данном компьютере корневым папкам. В Unix это папка "/", в Windows® – корневые папки всех возможных дисков. |
Пример работы с файловыми объектами:
File f1=new File(".."); // "." , "/" , "C:/../"
System.out.println("getAbsolutePath(): "+f1.getAbsolutePath());
try{
System.out.println("getCanonicalPath(): "+f1.getCanonicalPath());
}
catch(Exception e){
System.out.println("Исключение от getCanonicalPath() ");
};
System.out.println("exists(): "+f1.exists());
System.out.println("canRead(): "+f1.canRead());
System.out.println("canWrite(): "+f1.canWrite());
При работе с файлами в подавляющем большинстве приложений требуется вызов файлового диалога. В нашем приложении из JLabel ("Метка") – первый компонент в палитре . А затем повторим эту операцию еще раз. В первой метке мы будем показывать имя выбранного файла, а во второй – путь к этому файлу.
Для того, чтобы вызвать файловый диалог, назначим обработчик события пункту файлового меню openMenuItem ("Открыть...") – подузел [JFrame]/menuBar[JMenu]/fileMenu[JMenu]/openMenuItem[JMenuItem]. Двойной щелчок по узлу openMenuItem приводит к автоматическому созданию заготовки обработчика openMenuItemActionPerformed и открытию редактора исходного кода.
Сначала мы создаем в приложении объект типа JFileChooser, соответствующий файловому диалогу. Если в начале записать import javax., что желательно, то в соответствующих местах кода не потребуется квалификация javax.. Но в данном примере импорт не сделан намеренно для того, чтобы было видно, где используются классы данного пакета.
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();
Добавим в обработчик необходимый код:
private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
if(fileChooser.showOpenDialog(null)!= fileChooser.APPROVE_OPTION){
System.out.println("Отказались от выбора");
return;
};
System.out.println("Нажали Open");
jLabel1.setText(fileChooser.getSelectedFile().getName());
jLabel2.setText(fileChooser.getSelectedFile().getParent());
}
В первой строке обработчика вызывается метод fileChooser.showOpenDialog(openMenuItem). Он показывает диалог на экране. В качестве параметра должен быть задан родительский компонент – в этом качестве мы используем пункт меню openMenuItem. Сравнение с APPROVE_OPTION позволяет выяснить, была ли выбрана кнопка Open - "Открыть".
Следует обратить внимание на характерный прием – выход из подпрограммы с помощью оператора return в случае, когда не был осуществлен выбор файла. Неопытные программисты написали бы данный фрагмент кода таким образом:
if(fileChooser.showOpenDialog(openMenuItem)== fileChooser.APPROVE_OPTION){
System.out.println("Нажали Open");
jLabel1.setText(fileChooser.getSelectedFile().getName());
jLabel2.setText(fileChooser.getSelectedFile().getParent());
}
else
System.out.println("Отказались от выбора");
На первый взгляд принципиальной разницы нет. Но при усовершенствовании программы код, соответствующий выбору файла с помощью диалога, заметно разрастется, а код, соответствующий отказу от выбора, останется тем же. В результате практически весь код обработчика во втором варианте кода окажется вложенным в оператор if – а это может быть несколько страниц кода. В таком коде трудно разбираться. В первом варианте оператор if обладает небольшой областью действия, что позволяет легко разобраться с относящимся к нему кодом.
Можно было бы перенести строку
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser()
в обработчик события. В этом случае при каждом нажатии пункта меню "Файл/Открыть…" создавался бы новый объект-диалог. Такой код был бы работоспособен. Но создание диалога является относительно долгим процессом, требующим большого количества ресурсов операционной системы. Поэтому лучше создавать в приложении глобальную переменную, которой назначен диалог. Помимо прочего это позволяет в повторно открываемом диалоге оказываться в той же папке, где происходил последний выбор файла.
Перед вызовом диалога можно программно установить папку, в которой он будет открываться:
File folder=…; fileChooser.setCurrentDirectory(folder);
Диалог сохранения файла открывается аналогичным образом – showSaveDialog.
Практически всегда при использовании файловых диалогов требуется задавать фильтр, по которому просматриваются файлы. В подавляющем большинстве случаев требуется определенное расширение в имени файла. К сожалению, компонент JFileChooser до сих пор не поддерживает встроенной возможности настраивать фильтр – для этого требуется создание специального класса. Приведем пример простейшего такого класса:
package java_gui_example;
import java.io.*;
public class SimpleFileFilter extends javax.swing.filechooser.FileFilter {
String ext;
SimpleFileFilter(String ext){
this.ext=ext;
}
public boolean accept(File f){
if(f==null)
return false;
if(f.isDirectory()){
return true ;
}
else
return (f.getName().endsWith(ext));
}
/**
* Описание фильтра, возникающее в строке фильтра
* @see FileView#getName
*/
public String getDescription(){
return "Text files (.txt)";
}
}
Использование приведенного класса следующее: задается глобальная переменная
javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");
После чего она используется в обработчике события:
fileChooser.addChoosableFileFilter(fileFilter);
Данный оператор добавляет фильтр в выпадающий список возможных фильтров (масок) файлового диалога. Если добавляется уже существующий фильтр, операция добавления игнорируется.
По умолчанию показывается последний из добавленных фильтров. Если требуется показать другой фильтр, который уже был добавлен в список фильтров диалога, требуется вызвать оператор
fileChooser.setFileFilter(fileFilter);
Он делает добавленный фильтр текущим, то есть видимым при открытии диалога.
Кроме стандартных диалогов открытия и сохранения файлов имеется возможность вызова диалога с дополнительными программно задаваемыми элементами - с помощью метода showCustomDialog.
Также имеется возможность выбирать несколько файлов. Для этого до вызова диалога требуется задать разрешение на такой выбор:
fileChooser.setMultiSelectionEnabled(true);
Получение массива выбранных файлов после вызова диалога идет следующим образом:
java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null files.length > 0) {
String filenames = "";
for (int i=0; i<files.length; i++) {
filenames = filenames + "\n" + files[i].getPath();
}
}
Имеется возможность выбора папки (директории), а не файла. В этом случае следует задать режим, когда позволяется выбирать только папки
fileChooser.setFileSelectionMode(fileChooser.DIRECTORIES_ONLY);
либо и файлы, и папки
fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);
Возврат в обычный режим:
fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);
Для того, чтобы в выбранной папке просмотреть список файлов в папке, с которой связана переменная File folder, используется вызов вида
String[] filenames= folder.list(filter);
Получается массив строк с короткими именами файлов. Используется переменная filter, тип которой является классом, реализующим интерфейс java.io.FilenameFilter. О том, что такое интерфейсы, будет рассказано в отдельном разделе. Пример простейшего такого класса SimpleFilenameFilter:
package java_gui_example;
import java.io.*;
public class SimpleFilenameFilter implements FilenameFilter{
String ext;
public SimpleFilenameFilter(String ext) {
this.ext=ext;
}
public boolean accept(File dir,String fileName){
return ext==""||fileName.endsWith(ext);
}
}
Пример с показом файлов, содержащихся в выбранной папке, в компонент jTextArea1 (текстовая область) типа JTextArea, позволяющий показывать произвольное число строк:
String[] filenamesArray;
File folder=fileChooser.getSelectedFile();
SimpleFilenameFilter filter=new SimpleFilenameFilter("");
String filenames = "";
if(folder.isDirectory()){
filenamesArray=folder.list(filter);
for (int i=0; i<filenamesArray.length; i++) {
filenames = filenames + "\n" + filenamesArray[i];
};
jTextArea1.setText(filenames);
}
Аналогичный пример вывода выбранных в диалоге имен в режиме "мультиселект", позволяющем отмечать несколько файлов и/или папок:
java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null files.length > 0) {
String filenames = "";
for (int i=0; i<files.length; i++) {
filenames = filenames + "\n" + files[i].getPath();
};
jTextArea1.setText(filenames);
};
Стандартные классы Java, инкапсулирующие работу с данными (оболочечные классы для числовых данных, классы String и StringBuffer, массивы и т.д.), не обеспечивают поддержку чтения этих данных из файлов или запись их в файл. Вместо этого используется весьма гибкая и современная, но не очень простая технология использования потоков (Streams).
Поток представляет накапливающуюся последовательность данных, поступающих из какого-то источника. Порция данных может быть считана из потока, при этом она из потока изымается. В потоке действует принцип очереди – "первым вошел, первым вышел".
В качестве источника данных потока может быть использован как стационарный источник данных (файл, массив, строка), так и динамический – другой поток. При этом в ряде случаев выход одного потока может служить входом другого. Поток можно представить себе как трубу, через которую перекачиваются данные, причем часто в таких "трубах" происходит обработка данных. Например, поток шифрования шифрует данные, полученные на входе, и при считывании из потока передает их в таком виде на выход. А поток
Буферизуемые потоки имеют хранящийся в памяти промежуточный буфер, из которого считываются выходные данные потока. Наличие такого буфера позволяет повысить производительность операций ввода-вывода, а также осуществлять дополнительные операции – устанавливать метки (маркеры) для какого-либо элемента, находящегося в буфере потока и даже делать возврат считанных элементов в поток (в пределах буфера).
InputStream ("входной поток") инкапсулирует модель входных потоков, позволяющих считывать из них данные. OutputStream ("выходной поток") - модель выходных потоков, позволяющих записывать в них данные.
| Метод | Что делает |
|---|---|
int available() |
Текущее количество байт, доступных для чтения из потока. |
int read() |
Читает один байт из потока и возвращает его значение в виде целого, лежащего в диапазоне от 0 до 255. При достижении конца потока возвращает -1. |
int read(byte[] b)
|
Пытается прочесть b.length байт из потока в массив b. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
long |
Попытка пропускать (игнорировать) count байт из потока. count $$\le 0$$, пропуска байт нет. Возвращается реально пропущенное число байт. Если это значение $$\le 0$$, пропуска байт не было. |
boolean markSupported() |
Возвращает true в случае, когда поток поддерживает операции mark и reset, иначе – false. |
void mark(int limit) |
Ставит метку в текущей позиции начала потока. Используется для последующего вызова метода reset, с помощью которого считанные после установки метки данные возвращаются обратно в поток. Эту операцию поддерживают не все потоки. См. метод markSupported. |
void reset() |
Восстанавливает предшествующее состояние данных в начале потока, возвращая указатель начала потока на помеченный до того меткой элемент. То есть считанные после установки метки данные возвращаются обратно в поток. Попытка вызова при отсутствии метки или выходе ее за пределы лимита приводит к возбуждению исключения IOException. Эту операцию поддерживают не все потоки. См. методы markSupported и mark. |
void close() |
Закрытие потока. Последующие попытки чтения из этого потока приводят к возбуждению исключения IOException. |
Все методы класса InputStream, кроме markSupported и mark, возбуждают исключение IOException – оно возникает при ошибке чтения данных.
| Метод | Что делает |
|---|---|
void write(int b) |
Записывает один байт в поток. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу byte. Напомним, что в выражениях "короткие" целые типы автоматически преобразуются к типу int. |
void write(byte[] b)
|
Записывает в поток массив байт. Если заданы параметры offset и count, записывается не весь массив, а count байт начиная с индекса offset. |
void |
Форсирует вывод данных из выходного буфера и его очистку. Необходимость этой операции связана с тем, что в большинстве случаев данные уходят "во внешний мир" на запись не каждый раз после вызова write, а только после заполнения выходного буфера. Таким образом, если операции записи разделены паузой (большим интервалом времени), и требуется, чтобы уход данных из выходного буфера совершался своевременно, после последнего вызова оператора write, предшествующего паузе, надо вызывать оператор . |
void close() |
Закрытие потока. Последующие попытки записи в этот поток приводят к возбуждению исключения IOException. |
Все методы этого класса возбуждают IOException в случае ошибки записи.
Не все классы потоков являются потомками InputStream/OutputStream. Для чтения строк (в виде массива символов) используются потомки java.io. ("читатель"). В частности, для чтения из файла – класс FileReader. Аналогично, для записи строк используются классы - потомки java.io.Writer ("писатель"). В частности, для записи массива символов в файл – класс FileWriter.
Имеется еще один важный класс для работы с файлами, не входящий в иерархии InputStream/OutputStream и . Это класс RandomAccessFile ("файл с произвольным доступом"), предназначенный для чтения и записи данных в произвольном месте файла. Такой файл с точки зрения класса RandomAccessFile представляет массив байт, сохраненных на внешнем носителе. Класс RandomAccessFile не является абстрактным, поэтому можно создавать его экземпляры.
Все операции чтения и записи начинаются с позиции, задаваемой файловым указателем перед началом операции. После каждой такой операции файловый указатель сдвигается к концу файла на число позиций (байт), соответствующее типу считанных данных. В случае, когда во время записи файловый указатель выходит за конец файла, размер файла автоматически увеличивается.
| Метод | Что делает |
|---|---|
| Общие параметры файла | |
long getFilePointer() |
Возвращает значение файлового указателя - текущую позицию в файле считывающей/записывающей головки. Индексация начинается с нуля и дается в числе байт. |
long length() |
Длина файла (в байтах). |
void setLength(long newLength) |
Изменение длины файла – она устанавливается равной newLength. Если newLength меньше текущей длины, файл укорачивается путем отбрасывания его конца. При этом если файловый указатель находился в отбрасываемой части, он устанавливается в конец файла, иначе его позиция не меняется. Если newLength больше текущей длины, файл увеличивает размер путем добавления в конец нового пространства, содержимое которого не гарантируется. |
void close() |
Закрытие потока. Последующие попытки доступа к этому потоку приводят к возбуждению исключения IOException. |
| Побайтные операции установки позиции | |
void |
Установка файлового указателя в позицию . |
int skipBytes(int n) |
Пропуск n байт – передвижение считывающей/записывающей головки на n байт. Если $$n>0$$, то вперед, к концу файла. Если $$n\le 0$$, то позиция головки не меняется. Возвращается число реально пропущенных байт. Оно может быть меньше n – например, из-за достижения конца файла. |
| Побайтные операции чтения | |
int read() |
Читает один байт из потока и возвращает его значение в виде целого, лежащего в диапазоне от 0 до 255. При достижении конца потока возвращает -1. |
int read(byte[] b) |
Пытается прочесть b.length байт из потока в массив b. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
int read(byte[] b, int offset, int count) |
Пытается прочесть count байт из потока в массив b, записывая их начиная с позиции offset. Возвращает число реально прочитанных байт. После достижения конца потока последующие считывания возвращают -1. |
void readFully(byte[] b) |
Считывает из файла b.length байт, начиная с текущей позиции файлового указателя, и заполняет весь буферный массив b. |
void readFully(byte[] b, int offset, int count) |
Считывает из файла в массив count байт, записывая их начиная с байта, имеющего позицию offset. |
| Побайтные операции записи | |
void write(int b) |
b. То же, что writeByte(b). |
void write(byte[] b) |
b, т.е. b.length байт. |
void write(byte[] b, int offset, int count) |
count байт массива b начиная с байта массива, имеющего индекс offset. |
| Чтение одиночных значений примитивного типа | |
boolean readBoolean() |
Считывает значение boolean |
byte readByte() |
Считывает значение byte |
short readShort() |
Считывает значение short |
int readInt() |
Считывает значение int |
long readLong() |
Считывает значение long |
int readUnsignedByte() |
Считывает значение типа "беззнаковый байт"(тип отсутствует в Java) и преобразует в значение типа int |
int readUnsignedShort() |
Считывает значение типа "беззнаковое короткое целое"(тип отсутствует в Java) и преобразует в значение типа int |
char readChar() |
Считывает значение char |
float readFloat() |
Считывает значение float |
double readDouble() |
Считывает значение double |
| Запись одиночных значений примитивного типа | |
void writeBoolean(boolean v) |
boolean |
void writeByte(int v) |
byte. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу byte. |
void writeShort(int v) |
short. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу short. |
void writeInt(int v) |
int |
void writeLong(long v) |
long |
void writeChar(int v) |
char. Благодаря использованию типа int можно использовать в качестве параметра целочисленное выражение без приведения его к типу char. |
void writeFloat(float v) |
float |
void writeDouble(double v) |
double |
| Чтение отдельных строк | |
String readLine() |
Считывает из файла строку символов от текущей позиции файлового указателя до места переноса на новую строку (символ "\n" ) или конца файла. При этом старшие байты получившихся в строке символов UNICODE оказываются равными нулю, т.е. поддерживается только часть кодовой таблицы. Метод полезен для считывания текста, записанного в кодировке ANSI. |
String readUTF |
Считывает из файла строку символов в кодировке UTF-8 от текущей позиции файлового указателя. Число последующих считываемых байт строки в кодировке UTF-8 задается первыми двумя считанными байтами. |
| Запись отдельных строк | |
void writeBytes(String s) |
s как последовательности байт, соответствующих символам строки. При этом каждому символу соответствует один записываемый байт, так как у каждого символа UNICODE отбрасывается старший из двух байт ( записывается младший байт). Используется для записи символов в кодировке ANSI. См. также метод writeChars, в котором записываются оба байта. |
void writeChars(String s) |
s как последовательности байт, соответствующих символам строки. При этом каждому символу UNICODE соответствует два записываемых байта. |
void writeUTF(String s) |
|
Все методы класса RandomAccessFile, кроме getChannel(), возбуждают исключение IOException – оно возникает при ошибке записи или ошибке доступа к данным.
В конструкторе класса требуется указать два параметра. Первый – имя файла или
Например:
Рассмотрим примеры, иллюстрирующие работу с потоками.
Пример чтения текста из файла:
File file;
javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();
javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");
private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
fileChooser.addChoosableFileFilter(fileFilter);
if(fileChooser.showOpenDialog(null)!=fileChooser.APPROVE_OPTION){
return;//Нажали Cancel
};
file = fileChooser.getSelectedFile();
try{
InputStream fileInpStream=new FileInputStream(file);
int size=fileInpStream.available();
fileInpStream.close();
char[] buff=new char[size];
Reader fileReadStream=new FileReader(file);
int count=fileReadStream.read(buff);
jTextArea1.setText(String.copyValueOf(buff));
javax.swing.JOptionPane.showMessageDialog(null,
"Прочитано "+ count+" байт");
fileReadStream.close();
} catch(Exception e){
javax.swing.JOptionPane.showMessageDialog(null,
"Ошибка чтения из файла \n"+file.getAbsolutePath());
}
}
Переменной fileInpStream, которая будет использована для работы потока FileInputStream, мы задаем тип InputStream. Это очень характерный прием при работе с потоками, позволяющий при необходимости заменять в дальнейшем входной поток с FileInputStream на любой другой без изменения последующего кода. После выбора имени текстового файла с помощью файлового диалога мы создаем файловый поток:
fileInpStream=new FileInputStream(file);
Функция fileInpStream.available() возвращает число байт, которые можно считать из файла. После ее использования поток fileInpStream нам больше не нужен, и мы его закрываем. Поток FileReader не поддерживает метод available(), поэтому нам пришлось использовать поток типа FileInputStream.
Массив buff используется в качестве буфера, куда мы считываем весь файл.
Если требуется читать файлы большого размера, используют буфер фиксированной длины и в цикле считывают данные из файла блоками, равными длине буфера, до тех пор, пока число считанных байт не окажется меньше размера буфера. Это означает, что мы дошли до конца файла. В таком случае выполнение цикла следует прекратить. При такой организации программы нет необходимости вызывать метод available() и использовать поток типа FileInputStream.
В операторе
Reader fileReadStream=new FileReader(file);
используется тип , а не FileReader, по той же причине, что до этого мы использовали InputStream, а не FileInputStream.
Построчное чтение из файла осуществляется аналогично, но содержимое блока try следует заменить на следующий код:
FileReader filReadStream=new FileReader(file);
BufferedReader bufferedIn=new BufferedReader(filReadStream);
String s="",tmpS="";
while((tmpS=bufferedIn.readLine())!=null)
s+=tmpS+"\n";
jTextArea1.setText(s);
bufferedIn.close();
Пример записи текста в файл очень похож на пример чтения, но гораздо проще, так как не требуется вводить промежуточные буферы и потоки:
private void saveAsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
fileChooser.addChoosableFileFilter(fileFilter);
if(fileChooser.showSaveDialog(null)!=fileChooser.APPROVE_OPTION){
return;//Нажали Cancel
};
file = fileChooser.getSelectedFile();
try{
Writer filWriteStream=new FileWriter(file);
filWriteStream.write(jTextArea1.getText() );
filWriteStream.close();
} catch(Exception e){
javax.swing.JOptionPane.showMessageDialog(null,
"Ошибка записи в файл \n"+file.getAbsolutePath());
}
}
Иногда требуется использовать элементы, которые не являются ни числами, ни строками, но ведут себя как имена элементов и одновременно обладают порядковыми номерами. Например, названия месяцев или дней недели. В этих случаях используют перечисления. Для задания типа какого-либо перечисления следует написать зарезервированное слово (сокращение от
Тип-перечисление обязан быть глобальным – он может задаваться либо на уровне пакета, либо в каком-либо классе. Но его нельзя задавать внутри какого-либо метода. Элементы перечисления могут иметь любые имена, в том числе совпадающие в разных перечислениях или совпадающие с именами классов или их членов – каждое перечисление имеет свое собственное пространство имен. Доступ к элементу перечисления осуществляется с квалификацией именем типа-перечисления:
У каждого элемента перечисления имеется порядковый номер, соответствующий его положению в наборе - нумерация начинается с нуля. Поэтому первый элемент имеет номер 0, второй элемент – номер 1, и так далее. Имеется функция , возвращающая порядковый номер элемета в перечислении. Также имеется функция compareTo, позволяющая сравнивать два элемента перечисления - она возвращает разницу в их порядковых номерах.
Строковое представление значения можно получить с помощью функции name(). Преобразование из строки в значение типа "перечисление" осуществляется с помощью функции класса valueOf, в которую передается строковое представление значения.
Если требуется рассматривать элементы перечисления как массив, можно воспользоваться функцией values() – она возвращает массив элементов, к которым можно обращаться по индексу. Формат вызова функции такой: ИмяТипа.values()
Для примера зададим типы-перечисления Monthes ("месяцы") и
enum Monthes {jan,feb,mar,apr,may,jun,jul,aug,sept,oct,nov,dec};
enum Spring { march, apr, may };
Названия месяцев мы намеренно пишем со строчной буквы для того, чтобы было понятно, что это Monthes и для того, чтобы показать независимость их пространств имен. Объявление переменных типа "перечисление" делается так же, как для всех остальных типов, при этом переменные могут быть как неинициализированы, так и инициализированы при задании:
public Monthes m1 ,m2=Monthes.mar , m3; - при задании в классе общедоступных полей m1, m2 и m3,Spring spr1=Spring .apr , spr2; - при задании в методе локальной переменной или задании в классе поля spr1 с пакетным уровнем доступа.После чего возможны следующие операторы:
spr2=spr1;
spr1=Spring.may;
System.out.println("Результат сравнения="+spr2.compareTo(Spring.march));
После выполнения этих операторов в консольное окно будет выведен текст
Результат сравнения=1 ,
поскольку в переменной spr2 окажется значение порядковый номер которого на 1 больше, чем у значения с которым идет сравнение.
Пусть в переменной spr2 хранится значение . Порядковый номер значения, хранящегося в переменной, можно получить с помощью вызова spr2. Он возвратит число 2, так как may – третий элемент перечисления (сдвиг на 1 получается из-за того, что нумерация начинается с нуля).
Строковое представление значения, хранящегося в переменной spr2, можно получить с помощью вызова spr2.name(). Он возвратит строку "may" - имя типа в возвращаемое значение не входит.
Если переменная типа "перечисление" не инициализирована, в ней хранится значение null. Поэтому вызов
System.out.println("spr2="+spr2);
осуществленный до присваивания переменной spr2 значения возвратит строку
spr2=null
А вот попытки вызовов spr2. или spr2.name() приведут к возникновению ошибки (исключительной ситуации) с диагностикой
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Получение значения типа по номеру, хранящемуся в переменной i, осуществляется так:
spr1=Spring.values()[i];
Преобразование из строки в значение типа будет выглядеть так:
spr1=Spring.valueOf("march");
System.arraycopy. Быстрое заполнение массива одинаковыми значениями может осуществляться методом Arrays.fill - класс Arrays расположен в пакете java.util Поэлементное сравнение массивов следует выполнять с помощью метода Arrays.equals (сравнение на равенство содержимого массивов) либо Arrays.deepEquals (глубокое сравнение, то есть на равенство содержимого, а не ссылок – на произвольном уровне вложенности). Сортировка (упорядочение по значениям) массива производится методом Arrays.sort.String инкапсулирует действия со строками. Объект типа String – строка, состоящая из произвольного числа символов, от 0 до $$2*10^9$$. Литерные константы типа String представляют собой последовательности символов, заключенные в двойные кавычки. В классе Object имеется метод toString(), обеспечивающий строковое представление любого объекта.String являются неизменяемыми объектами – при каждом изменении содержимого строки создается новый объект-строка. Для того чтобы сделать работу с многочисленными присваиваниями более эффективной, используются классы StringBuffer и StringBuilder.java.awt .Graphics. Для того, чтобы результаты вывода не пропадали, в paint, вызываемый при отрисовке. А также обработчик события ComponentResized.Throwable. От Throwable наследуются классы Error ("Ошибка") и Exception ("Исключение"). Экземплярами класса Error являются непроверяемые исключительные ситуации, которые невозможно перехватить в блоках catch. Экземплярами класса Exception и его потомков являются проверяемые исключительные ситуации. Кроме одного потомка – класса RuntimeException (и его потомков).throws в заголовке метода указывать не надо. Если же в теле реализуемого метода используется вызов метода, который может возбуждать исключительную ситуацию, и это исключение не перехватывается, в заголовке реализуемого метода требуется указывать соответствующий тип возбуждаемого исключения.File обеспечивают работу с именами файлов и папок (проверка существования файла или папки с заданным именем, нахождение абсолютного пути по относительному и наоборот, проверка и установка JFileChooser (пакет javax.InputStream ("входной поток") инкапсулирует модель входных потоков, позволяющих считывать из них данные. OutputStream ("выходной поток") - модель выходных потоков, позволяющих записывать в них данные.Reader ("читатель"). В частности, для чтения из файла – класс FileReader. Аналогично, для записи строк используются классы- потомки Writer ("писатель"). В частности, для записи массива символов в файл – класс FileWriter.RandomAccessFile ("файл с произвольным доступом"), предназначенный для чтения и записи данных в произвольном месте файла. Такой файл с точки зрения класса RandomAccessFile представляет массив байт, сохраненных на внешнем носителе. Класс RandomAccessFile не является абстрактным, поэтому можно создавать его экземпляры.FileInputStream/FileOutputStream (потомков InputStream/OutputStream ). Использовать диалоги выбора файлов.RandomAccessFile. Использовать диалоги выбора файлов.JTextArea и считывания их из файла с помощью класса RandomAccessFile. Использовать диалоги выбора файлов. Проверить работу с русским языком при записи и чтении текста в различных кодировках (ANSI, UNICODE,UTF-8).JTable. Действия проводить с помощью массивов чисел типа double.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.