- •Краткая историческая справка.
- •Преимущества языка Java.
- •Недостатки java:
- •Лекция 2. Этапы разработки java-приложений. Этапы разработки java-приложений.
- •Установка jdk.
- •Инсталляция исходных кодов библиотек
- •Инсталляция пакета документации.
- •Тестирование правильности установки и создание простейшей программы
- •Визуальные среды программирования.
- •Лекция 3. Переменные и типы данных. Переменные и типы данных.
- •Подробности о примитивных типах.
- •Лекция 4. Операторы и функции. Операторы и функции.
- •Операторы ветвлений и циклов.
- •Оператор цикла while.
- •Оператор цикла for.
- •Лекция 5. Объектно ориентированное программирование Объектно ориентированное программирование.
- •Определение объекта.
- •Инкапсуляция.
- •Наследование.
- •Полиморфизм (перегрузка).
- •Пример ооп – программы.
- •Отличие перегрузки функций от переопределения.
- •Отличие классов от интерфейсов.
- •Лекция 6. Массивы и строки. Массивы и строки.
- •Многомерные массивы.
- •Приведение типов и динамические массивы.
- •Строки в java.
- •Лекция 7. Организация ввода-вывода данных Организация ввода-вывода данных.
- •Функции стандартной библиотеки ввода/вывода.
- •Новая библиотека ввода/вывода.
- •Классы потокового ввода/вывода из пакета java.Io.
- •Лекция 8. Обработка исключений. Обработка исключений.
- •Классификация исключений.
- •Перехват исключений блоками try/catch.
- •Самостоятельное выбрасывание исключений.
- •Разработка собственных классов исключений.
- •Лекция 9. Потоки. Потоки.
- •1. Cпециальный класс Thread.
- •2. Реализация интерфейса Runnable.
- •Выбор между использованием класса Thread и интерфейса Runnable.
- •Синхронизация потоков с помощью оператора synchronized.
- •Синхронизация потоков с помощью семафоров.
- •Лекция 10. Подключаемые библиотеки java. Подключаемые библиотеки java.
- •Библиотека awt
- •Внутреннее устройство системы обработки событий awt.
- •Библиотека Swing.
Многомерные массивы.
Для объявления двумерного массива достаточно поставить еще одни скобки.
int [] [] a = new int[10][10];
После инициализации такого массива, к его элементам можно обращаться по отдельным индексам: a[i][j]; Однако многомерные массивы java имеют особенность. На самом деле все массивы в java одномерные. Если вы объявляете, например, двумерный массив, это тоже будет одномерный массив, просто все элементы его будут одномерными массивами.
То есть это массив массивов.
С программной точки зрения это удобно тем, что появляется возможность задавать неквадратные массивы, а также обнулять отдельные элементы двумерного массива, присваивая им null.
int[][] a = {
{1,2,3,4,5},
{1,2},
null,
{1,2,3},
{1}
};
System.out.println(Arrays.deepToString(a));
На экране будет напечатано:
[[1, 2, 3, 4, 5], [1, 2], null, [1, 2, 3], [1]]
Обратите также внимание, что для распечатки многомерного массива предусмотрен специальный метод Arrays.deepToString(a).
Перебор массивов можно делать с помощью цикла for, или с помощью цикла for-each:
for(int i=0; i < a.length; i++) { System.out.println(a[i]); }
Но значения двумерных (и вообще многомерных массивов) – это тоже массивы, поэтому чтобы добраться до конечных значений, требуются вложенные циклы.
int [] [] a = new int[10][10];
…
for(int[] row: a) {
for(int elem: row) {
…
}
Приведение типов и динамические массивы.
В процессе использования массивов для хранения различных часто меняющихся данных возникает проблема, связанная с заданием размеров массива. Очень часто программист не знает заранее, сколько элементов должен содержать массив и какого они могут быть типа.
Проблема с типом содержимого массива решается достаточно просто. Можно объявить массив обобщенного типа Object и хранить в нем данные разных типов:
import java.util.Arrays;
…
Object[] a = new Object[5];
a[1] = 10;
a[2] = "sfggf";
System.out.println("a="+ Arrays.toString(a));
Напечатает: a=[null, 10, sfggf, null, null]
С точки зрения рационального расходования памяти это не слишком эффективно, но вполне допустимо. Однако, в этом случае вы должны учитывать, что компилятор ничего не знает о том, какой конкретно тип объекта хранится в данной ячейке массива. Такой код, к примеру, будет давать ошибку:
String c;
Object[] a = new Object[5];
a[1] = 10;
a[2] = "3";
c = a[2]; // Ошибка! Несмотря на то, что в ячейке именно строка!
System.out.println("c="+ c);
Для того, чтобы компилятор понимал, с каким конкретно типом объектов он имеет дело, этот тип нужно указывать явно перед операцией присвоения переменной. Вот такой код сработает нормально:
String c;
Object[] a = new Object[5];
a[1] = 10;
a[2] = "3";
c = (String) a[2];
System.out.println("c="+ c);
Но операция явного указания типа всего – лишь указывает компилятору, какой конкретно тип используется в данном случае, но не приводит тип операнда к нужному типу. Компилятор просто не считает себя умнее программиста и не проводит операцию автоматического преобразования типов. Вот такой код снова будет давать ошибку:
int c;
Object[] a = new Object[5];
a[1] = 10;
a[2] = "3";
c = (int) a[2];
с = с – 1; // Опять ошибка!
System.out.println("c="+ c);
Для перевода строки в число необходимо произвести операцию явного преобразования типа. В каждом базовом классе для этого предусмотрены специальные методы, в частности, в классах String и Integer такими методами является метод valueOf():
int c;
Object[] a = new Object[5];
a[1] = 10;
a[2] = "3";
c = Integer.valueOf((String) a[2]);
с = с – 1; // Теперь ошибок нет.
System.out.println("c="+ c);
Данная операция называется «Приведение типа». Она возможна, если тип к которому приводят занимает больше ячеек памяти, чем тип, который преобразовывают.
Например, вот такой код сработает нормально, потому что число 123 меньше одного байта.
Byte b1;
b1 = Byte.valueOf("123");
System.out.println(b1);
А такой код выдаст ошибку, поскольку число 300 заведомо больше:
Byte b1;
b1 = Byte.valueOf("300"); // Ошибка!
System.out.println(b1);
Очень часто встречаются ситуация, когда размер массива должен быть увеличен или уменьшен в процессе выполнения программы. Например, если мы храним в нем список абонентов какой-либо услуги, а абоненты услуги при этом то подключаются к ней, то отписываются от неё. Можно конечно попытаться задать размер списка «с запасом», но практика показывает, что какого бы размера массив мы не задали, в момент пиковой нагрузки на систему, список все-равно может быть переполнен и возникнет ошибка выхода за границы массива.
Для этих целей в java предусмотрены специальные классы, реализующие интерфейс взаимодействия с динамическими массивами. Всю сложность поддержания актуального размера массива вне зависимости от количества добавляемых элементов и указателей на текущий элемент массива они берут на себя. Платой за это удобство является некоторое усложнение синтаксиса обращения к ним. Примером такого класса может служить класс Vector:
import java.util.Vector; // импортируем класс Vector из пакета util
…
Vector v = new Vector(); // объявляем переменную, типа Vector
v.add(1); // последовательно добавляем элементы ..
v.add(2);
v.add("fghjg");
v.add(4);
System.out.println("v="+ v);
v.remove(2); // удаляем элемент с индексом 2
System.out.println("v="+ v);
v.set(1, "rrrr"); // перезаписываем элемент с индексом 1
System.out.println("v="+ v);
Напечатает:
v=[1, 2, fghjg, 4]
v=[1, 2, 4]
v=[1, rrrr, 4]
