Контрольная работа
Программирование на Java (теория)
СОДЕРЖАНИЕ
1. Динамическая инициализация объектов
2. Чтение и запись файлов
1. Динамическая инициализация объектов
Объекты в Java создаются с помощью зарезервированного слова new, после которого идет конструктор – специальная подпрограмма, занимающаяся созданием объекта и инициализацией полей создаваемого объекта. Для него не указывается тип возвращаемого значения, и он не является ни методом объекта (вызывается через имя класса когда объекта еще нет), ни методом класса (в конструкторе доступен объект и его поля через ссылку this). На самом деле конструктор в сочетании с оператором new возвращает ссылку на создаваемый объект и может считаться особым видом методов, соединяющим в себе черты методов класса и методов объекта.
Если в объекте при создании не нужна никакая дополнительная инициализация, можно использовать конструктор, который по умолчанию присутствует для каждого класса. Это имя класса, после которого ставятся пустые круглые скобки – без списка параметров. Такой конструктор при разработке класса задавать не надо, он присутствует автоматически. Если требуется инициализация, обычно применяют конструкторы со списком параметров.
Порядок вызовов при создании объекта некого класса (будем называть его дочерним классом):
1. Создается объект, в котором все поля данных имеют значения по умолчанию (нули на двоичном уровне представления).
2. Вызывается конструктор дочернего класса.
3. Конструктор дочернего класса вызывает конструктор родителя (непосредственного прародителя), а также по цепочке все прародительские конструкторы и инициализации полей, заданных в этих классах, вплоть до класса Object.
4. Проводится инициализация полей родительской части объекта значениями, заданными в декларации родительского класса.
5. Выполняется тело конструктора родительского класса.
6. Проводится инициализация полей дочерней части объекта значениями, заданными в декларации дочернего класса.
7. Выполняется тело конструктора дочернего класса.
Знание данного порядка важно в случаях, когда в конструкторе вызываются какие-либо методы объекта, и надо быть уверенным, что к моменту вызова этих методов объект получит правильные значения полей данных.
Как правило, для инициализации полей сложно устроенных объектов используют конструкторы. Но кроме них в Java, в отличие от большинства других языков программирования, для этих целей могут также служить блоки инициализации класса и блоки инициализации объекта. Синтаксис задания классов с блоками инициализации следующий:
Модификаторы class ИмяКласса extends ИмяРодителя {
Задание полей;
static {
тело блока инициализации класса
}
{
тело блока инициализации объекта
}
Задание подпрограмм - методов класса, методов объекта, конструкторов
}
Блоков инициализации класса и блоков инициализации объекта может быть несколько.
Порядок выполнения операторов при наличии блоков инициализации главного класса приложения (содержащего метод main):
1. инициализация полей данных и выполнение блоков инициализации класса (в порядке записи в декларации класса);
2. метод main;
3. выполнение блоков инициализации объекта;
4. выполнение тела конструктора класса.
Для других классов порядок аналогичен, но без вызова метода main:
1. инициализация полей данных и выполнение блоков инициализации класса (в порядке записи в декларации класса);
2. выполнение блоков инициализации объекта;
3. выполнение тела конструктора класса.
Чем лучше пользоваться, блоками инициализации или конструкторами? Ответ, конечно, неоднозначен: в одних ситуациях – конструкторами, в других – блоками инициализации. Для придания начальных значений переменным класса в случаях, когда для этого требуются сложные алгоритмы, можно пользоваться только статическими блоками инициализации. Для инициализации полей объектов в общем случае лучше пользоваться конструкторами, но если необходимо выполнить какой-либо код инициализации до вызова унаследованного конструктора, можно воспользоваться блоком динамической инициализации.
Приведем несколько примеров. Программа SmallSquares (маленькие квадраты) возвращает квадрат маленького целого числа. SmallSquares имеет две статические переменные и единственную открытую статическую функцию getSquare().
public class SmallSquares {
private static final int LIMIT = 10;
private static final int[] square = new int[LIMIT];
public SmallSquares() {
for (int i = 0; i < LIMIT; i++) {
square[i] = i * i;
}
}
}
public static int getSquare(int i) {
return square[i];
}
public static void main(String[] args) {
new SmallSquares();
System.out.println("3 squared is " +
getSquare(3));
}
}
Откомпилировав и запустив SmallSquares, получим следующий результат:
3 squared is 9 (3 в квадрате будет 9)
В данном коде объект создается при помощи конструктора так называемым статическим методом.
Приведем пример статической инициализации. За словом статический (static) следует блок кода, окруженного фигурными скобками. Можно использовать статический блок для инициализации массива квадратов следующим образом:
static {
for (int i = 0; i < LIMIT; i++) {
square[i] = i * i;
}
}
Статический блок запрашивается только один раз во время создания класса. Теперь не нужен конструктор, и можно вызывать статическую функцию getSquare() без предшествующего создания класса. Улучшенныйкодвыглядитследующимобразом:
public class SmallSquares {
private static final int LIMIT = 10;
private static final int[] square = new int[LIMIT];
static {
for (int i = 0; i < LIMIT; i++) {
square[i] = i * i;
}
}
public static int getSquare(int i) {
// Нет обработки ошибки, предположим,0<=i<limit
return square[i];
}
public static void main(String[] args) {
System.out.println("3 squared is " + getSquare(3));
}
}
Приведем пример применения блока динамической инициализации. Код в программе, ConstructorExample (пример конструктора), снова инициализирует массив целых чисел. Существует две версии конструктора. Первая - конструктор без аргумента, который по умолчанию определяет значение "Безымянный" ("Anonymous"). Во второй версии есть один аргумент: значение имя пользователя (userName). Конструкторы объединены, так как квадрат должен инициализироваться в каждом случае.
public class ConstructorExample {
private final String userName;
private final static int[] square = new int[10];
public ConstructorExample() {
this("Anonymous");
}
public ConstructorExample(String userName) {
this.userName = userName;
for (int i = 0; i < 10; i++) {
square[i] = i * i;
}
}
public void printSquare(int i) {
// no error handling - assume 0<=i<limit
System.out.println("Hello " + userName);
System.out.println(i + " squared is " + square[i]);
}
public static void main(String[] args) {
new ConstructorExample().printSquare(3);
new ConstructorExample("Ed").printSquare(5);
}
}
Откомпилируем и запустим ConstructorExample. В итоге получим следующий результат:
Hello Anonymous (привет Безымянный)
3 squared is 9 (3 в квадрате будет 9)
Hello Ed (Привет Эд)
5 squared is 25 (5 в квадрате будет 25)
В приведенном выше примере квадрат инициализируется не правильно в зависимости от того, вызывает ли пользователь конструктор без аргумента или использует сигнатуру, требующую строку (String). Пример конструктора можно привести в порядок, переместив поле инициализатора для имени пользователя (userName) и введя следующий блок инициализатора:
{
for (int i = 0; i < 10; i++) {
square[i] = i * i;
}
}
Данный блок инициализаторов выглядит как блок статического инициализатора без статического ключевого слова. Он запускается перед тем, как вызвать конструктор.
Можно разделить конструкторы в примере (ConstructorExample), передвинув следующие строки от конструктора без аргумента:
this("Anonymous");
В следующей программе появляется пустой конструктор, ConstructorExample2 (пример конструктора 2), чтобы продемонстрировать введение данного блока инициализации.
public class ConstructorExample2 {
private final String userName;
private static final int[] square = new int[10];
{
for (int i = 0; i < 10; i++) {
square[i] = i * i;
}
}
public ConstructorExample2() {
userName = "Anonymous";
}
public ConstructorExample2(String userName) {
this.userName = userName;
}
public void printSquare(int i) {
// Нет обработки ошибки, предположим,0<=i<limit
System.out.println("Hello " + userName);
System.out.println(i + " squared is " + square[i]);
}
public static void main(String[] args) {
new ConstructorExample2().printSquare(3);
new ConstructorExample2("Ed").printSquare(5);
}
}
Однажды, попробовав работать с блоками инициализации, возможно найти для них много приложений. Можно убедиться, что статические и динамические инициализаторы очень удобные.
инициализация java файл программа
2. Чтение и запись файлов
Подавляющее большинство программ обменивается данными с внешним миром. Это, безусловно, делают любые сетевые приложения – они передают и получают информацию от других компьютеров и специальных устройств, подключенных к сети. Оказывается, можно точно таким же образом представлять обмен данными между устройствами внутри одной машины. Так, например, программа может считывать данные с клавиатуры и записывать их в файл, или же наоборот - считывать данные из файла и выводить их на экран. Таким образом, устройства, откуда может производиться считывание информации, могут быть самыми разнообразными – файл, клавиатура, входящее сетевое соединение и т.д. То же касается и устройств вывода – это может быть файл, экран монитора, принтер, исходящее сетевое соединение и т.п. В конечном счете, все данные в компьютерной системе в процессе обработки передаются от устройств ввода к устройствам вывода.
Обычно часть вычислительной платформы, которая отвечает за обмен данными, так и называется – система ввода/вывода. В Java она представлена пакетом java.io (input/output). Реализация системы ввода/вывода осложняется не только широким спектром источников и получателей данных, но еще и различными форматами передачи информации. Ею можно обмениваться в двоичном представлении, символьном или текстовом, с применением некоторой кодировки (только для русского языка их насчитывается более 4 штук), или передавать числа в различных представлениях. Доступ к данным может потребоваться как последовательный (например, считывание HTML-страницы), так и произвольный (сложная работа с несколькими частями одного файла). Зачастую для повышения производительности применяется буферизация.