русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Инициализация нестатических данных экземпляра


Дата добавления: 2015-06-12; просмотров: 765; Нарушение авторских прав


В Java имеется сходный синтаксис для инициализации нестатических переменных для каждого объекта. Вот пример: .

//: initialization/Mugs.java

// "Инициализация экземпляра"

import static net.mindview.util.Print.*;

 

class Mug {

Mug(int marker) {

print("Mug(" + marker + ")");

}

void f(int marker) {

print("f(" + marker + ")");

}

}

 

public class Mugs {

Mug mug1;

Mug mug2;

{

mug1 = new Mug(1);

mug2 = new Mug(2);

print("mug1 & mug2 initialized");

}

Mugs() {

print("Mugs()");

}

Mugs(int i) {

print("Mugs(int)");

}

public static void main(String[] args) {

print("Inside main()");

new Mugs();

print("new Mugs() completed");

new Mugs(1);

print("new Mugs(1) completed");

}

}

<spoiler text="Output:">

Inside main()

Mug(1)

Mug(2)

mug1 & mug2 initialized

Mugs()

new Mugs() completed

Mug(1)

Mug(2)

mug1 & mug2 initialized

Mugs(int)

new Mugs(1) completed

</spoiler> выглядит в точности так же, как и конструкция static-инициализации, разве что ключевое слово static отсутствует. Такой синтаксис необходим для поддержки инициализации анонимных внутренних классов (см. главу 9), но он также гарантирует, что некоторые операции будут выполнены независимо от того, какой именно конструктор был вызван в программе. Из результатов видно, что секция инициализации экземпляра выполняется раньше любых конструкторов.

 

Инициализация массивов

Массив представляет собой последовательность объектов или примитивов, относящихся к одному типу, обозначаемую одним идентификатором. Массивы определяются и используются с помощью оператора индексирования [ ]. Чтобы объявить массив, вы просто. указываете вслед за типом пустые квадратные скобки:



int[] al;

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

int al[];

Это соответствует ожиданиям программистов на C и C++, привыкших к такому синтаксису. Впрочем, первый стиль, пожалуй, выглядит более логично — он сразу дает понять, что имеется в виду «массив значений типа int». Он и будет использоваться в книге.

Компилятор не позволяет указать точный размер массива. Вспомните, что говорилось ранее о ссылках. Все, что у вас сейчас есть, — это ссылка на массив, для которого еще не было выделено памяти. Чтобы резервировать память для массива, необходимо записать некоторое выражение инициализации. Для массивов такое выражение может находиться в любом месте программы, но существует и особая разновидность выражений инициализации, используемая только в точке объявления массива. Эта специальная инициализация выглядит как набор значений в фигурных скобках. Выделение памяти (эквивалентное действию оператора new) в этом случае проводится компилятором. Например:

int[] al = { 1, 2, 3, 4, 5 };

Но зачем тогда вообще нужно определять ссылку на массив без самого массива?

int[] а2;

Во-первых, в Java можно присвоить один массив другому, записав следующее:

а2 = al;

В данном случае вы на самом деле копируете ссылку, как показано в примере:

//: initialization/ArraysOfPrimitives.java

// Массивы простейших типов.

import static net.mindview.util.Print.*;

 

public class ArraysOfPrimitives {

public static void main(String[] args) {

int[] a1 = { 1, 2, 3, 4, 5 };

int[] a2;

a2 = a1;

for(int i = 0; i < a2.length; i++)

a2[i] = a2[i] + 1;

for(int i = 0; i < a1.length; i++)

print("a1[" + i + "] = " + a1[i]);

}

}

<spoiler text="Output:">

a1[0] = 2

a1[1] = 3

a1[2] = 4

a1[3] = 5

a1[4] = 6

</spoiler> Массив a1 инициализируется набором значений, в то время как массив а2 — нет; присваивание по ссылке а2 присваивается позже — в данном случае присваивается другой массив.

Все массивы (как массивы примитивов, так и массивы объектов) содержат поле> которое можно прочитать (но не изменить!) для получения количества элементов в массиве. Это поле называется length. Так как в массивах Java, C и C++ . Нумерация элементов начинается с нуля, последнему элементу массива соответствует индекс length—1. При выходе за границы массива C и C++ не препятствуют «прогулкам в памяти» программы, что часто приводит к печальным последствиям. Но Java защищает вас от таких проблем — при выходе за рамки массива происходит ошибка времени исполнения (исключение, тема главы 10).

А если во время написания программы вы не знаете, сколько элементов вам понадобится в новом массиве? Тогда просто используйте new для создания его элементов. В следующем примере new работает, хотя в программе создается массив примитивных типов (операторnew неприменим для создания примитивов вне массива):

//: initialization/ArrayNew.java

// Создание массивов оператором new.

import java.util.*;

import static net.mindview.util.Print.*;

 

public class ArrayNew {

public static void main(String[] args) {

int[] a;

Random rand = new Random(47);

a = new int[rand.nextInt(20)];

print("length of a = " + a.length);

print(Arrays.toString(a));

}

}

<spoiler text="Output:">

length of a = 18

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

</spoiler> Размер массива выбирается случайным образом, с использованием метода Random.nextInt(), генерирующего число от нуля до переданного в качестве аргумента значения. Так как размер массива случаен, очевидно, что создание массива происходит во время исполнения программы. Вдобавок, результат работы программы позволяет убедиться в том, что элементы массивов простейших типов автоматически инициализируются «пустыми» значениями. (Для чисел и символов это ноль, а для логического типа boolean — false.)

Метод Arrays.toString(), входящий в стандартную библиотеку java.util, выдает печатную версию одномерного массива.

Конечно, в данном примере массив можно определить и инициализировать в одной строке:

int[] а = new int[rand.nextInt(20)];

Если возможно, рекомендуется использовать именно такую форму записи. При создании массива непримитивных объектов вы фактически создаете массив ссылок. Для примера возьмем класс-обертку Integer, который является именно классом, а не примитивом:

//: initialization/ArrayClassObj.java

// Создание массива непримитивных объектов.

import java.util.*;

import static net.mindview.util.Print.*;

 

public class ArrayClassObj {

public static void main(String[] args) {

Random rand = new Random(47);

Integer[] a = new Integer[rand.nextInt(20)];

print("length of a = " + a.length);

for(int i = 0; i < a.length; i++)

a[i] = rand.nextInt(500); // Автоматическая упаковка

print(Arrays.toString(a));

}

}

<spoiler text="Output:"> (Sample)

length of a = 18

[55, 193, 361, 461, 429, 368, 200, 22, 207, 288, 128, 51, 89, 309, 278, 498, 361, 20]

</spoiler> Здесь даже после вызова new для создания массива

Integer[] а = new Integer[rand nextlnt(20)];

мы имеем лишь массив из ссылок — до тех пор, пока каждая ссылка не будет инициализирована новым объектом Integer (в данном случае это делается посредством автоупаковки):

a[i] = rand.nextlnt(500);

Если вы забудете создать объект, то получите исключение во время выполнения программы, при попытке чтения несуществующего элемента массива. Массивы объектов также можно инициализировать списком в фигурных скобках. Существует две формы синтаксиса:

//: initialization/ArrayInit.java

// Инициализация массивов

import java.util.*;

 

public class ArrayInit {

public static void main(String[] args) {

Integer[] a = {

new Integer(1),

new Integer(2),

3, // Autoboxing

};

Integer[] b = new Integer[]{

new Integer(1),

new Integer(2),

3, // Автоматическая упаковка

};

System.out.println(Arrays.toString(a));

System.out.println(Arrays.toString(b));

}

}

<spoiler text="Output:">

[1, 2, 3]

[1, 2, 3]

</spoiler> В обоих случаях завершающая запятая в списке инициализаторов не обязательна (она всего лишь упрощает ведение длинных списков). Первая форма полезна, но она более ограничена, поскольку может использоваться только в точке определения массива. Вторая форма может использоваться везде, даже внутри вызова метода.

Списки аргументов переменной длины

Синтаксис второй формы предоставляет удобный синтаксис создания и вызова методов с эффектом, напоминающим списки аргументов переменной длины языка C. Такой список способен содержать неизвестное заранее количество аргументов неизвестного типа. Так как абсолютно все классы унаследованы от общего корневого класса Object, можно создать метод, принимающий в качестве аргумента массив Object, и вызывать его следующим образом:

//: initialization/VarArgs.java

// Использование синтаксиса массивов

// для получения переменного списка параметров.

class A {}

 

public class VarArgs {

static void printArray(Object[] args) {

for(Object obj : args)

System.out.print(obj + " ");

System.out.println();

}

public static void main(String[] args) {

printArray(new Object[]{

new Integer(47), new Float(3.14), new Double(11.11)

});

printArray(new Object[]{"one", "two", "three" });

printArray(new Object[]{new A(), new A(), new A()});

}

}

<spoiler text="Output:"> (Sample)

47 3.14 11.11

one two three

A@1a46e30 A@3e25a5 A@19821f

</spoiler> Видно, что метод print() принимает массив объектов типа Object, перебирает его элементы и выводит их. Классы из стандартной библиотеки Java при печати выводят осмысленную информацию, однако объекты классов в данном примере выводят имя класса, затем символ @ и несколько шестнадцатеричных цифр. Таким образом, по умолчанию класс выводит имя и адрес объекта (если только вы не переопределите в классе метод toString() — см. далее).

До выхода Java SE5 переменные списки аргументов реализовывались именно так. В Java SE5 эта долгожданная возможность наконец-то была добавлена в язык — теперь для определения переменного списка аргументов может ис­пользоваться многоточие, как видно в определении метода printArray:

//: initialization/NewVarArgs.java

/ Создание списков аргументов переменной длины

// с использованием синтаксиса массивов.

public class NewVarArgs {

static void printArray(Object... args) {

for(Object obj : args)

System.out.print(obj + " ");

System.out.println();

}

public static void main(String[] args) {

// Можно передать отдельные элементы:

printArray(new Integer(47), new Float(3.14),

new Double(11.11));

printArray(47, 3.14F, 11.11);

printArray("one", "two", "three");

printArray(new A(), new A(), new A());

// Или массив:

printArray((Object[])new Integer[]{ 1, 2, 3, 4 });

printArray(); // Пустой список тоже возможен

}

}

<spoiler text="Output:"> (75% match)

47 3.14 11.11

47 3.14 11.11

one two three

A@1bab50a A@c3c749 A@150bd4d

1 2 3 4

</spoiler>

 

Резюме

Такой сложный механизм инициализации, как конструктор, показывает, насколько важное внимание в языке уделяется инициализации. Когда Бьерн Страуструп разрабатывал C++, в первую очередь он обратил внимание на то, что низкая продуктивность C связана с плохо продуманной инициализацией, которой была обусловлена значительная доля ошибок. Аналогичные проблемы возникают и при некорректной финализации. Так как конструкторы позволяют гарантировать соответствующие инициализацию и завершающие действия по очистке (компилятор не позволит создать объект без вызова конструктора), тем самым обеспечивается полная управляемость и защищенность программы.

В языке C++ уничтожение объектов играет очень важную роль, потому что объекты, созданные оператором new, должны быть соответствующим образом разрушены. В Java память автоматически освобождается сборщиком мусора, и аналоги деструкторов обычно не нужны. В таких случаях сборщик мусора Java значительно упрощает процесс программирования и к тому же добавляет так необходимую безопасность при освобождении ресурсов. Некоторые сборщики мусора могут проводить завершающие действия даже с такими ресурсами, как графические и файловые дескрипторы. Однако сборщики мусора добавляют издержки во время выполнения программы, которые пока трудно реально оценить из-за сложившейся исторически медлительности интерпретаторов Java. И хотя в последнее время язык Java намного улучшил свою производительность, проблема его «задумчивости» все-таки наложила свой отпечаток на возможность решения языком некоторого класса задач.

Так как для всех объектов гарантированно используются конструкторы, на последние возлагаются дополнительные обязанности, не описанные в этой главе. В частности, гарантия конструирования действует и при создании новых классов с использованием композиции или наследования, и для их поддержки требуются некоторые дополнения к синтаксису языка. Композиция и наследование, а также их влияние на конструкторы, рассматриваются в следующих главах.


 



<== предыдущая лекция | следующая лекция ==>
Явная инициализация статических членов | Глава 6 УПРАВЛЕНИЕ ДОСТУПОМ


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.22 сек.