Объекты. Создание и сохранение объектов классов. Оператор new. Области сохранения данных в памяти. Использование массивов ссылок на объекты

Объекты. Создание и сохранение объектов классов. Оператор new. Области сохранения данных в памяти. Использование массивов ссылок на объекты


Содержание


1. Каким образом создается объект класса с помощью оператора new? Общая форма

В Java для работы с объектами используется единый синтаксис. Объект класса объявляется с помощью ссылки (reference).
Общая форма объявления объекта класса без выделения памяти для него имеет следующий вид:

ClassName objName;

где

  • ClassName – имя класса для которого создается объект с именем objName;
  • objName – имя ссылки на объект класса ClassName.
    Вышеприведенное объявление говорит о том, что идентификатор objName есть ссылкой на объект класса ClassName. Для ссылки нужно выделить память (инициализировать ссылку) с помощью оператора new как показано ниже:
objName = new ClassName();

Если не выделить память для ссылки и обратиться к нему как к объекту класса, то возникнет ошибка.

Существует и другая общая форма объявления объекта класса. В этом случае память выделяется при его объявлении:

ClassName objName = new ClassName();

Выделение памяти для ссылки на объект класса еще называется «присоединение» объекта к ссылке.

2. Примеры создания объектов разных классов

Пример 1. Создание объекта класса CLine, реализующего линию на координатной плоскости. Программный код объявления класса следующий:

// класс, который реализует линию на координатной плоскости
public class CLine
{
    // внутренние переменные класса
    private double x1, y1, x2, y2;

    // конструкторы класса
    // конструктор без параметров
    CLine()
    {
        x1 = y1 = 0;
        x2 = y2 = 1;
    }

    // конструктор с 4 параметрами
    CLine(double x1, double y1, double x2, double y2)
    {
        this.x1 = x1; this.y1 = y1;
        this.x2 = x2; this.y2 = y2;
    }

    // методы доступа
    // чтение данных
    public double GetX1() { return x1; }
    public double GetY1() { return y1; }
    public double GetX2() { return x2; }
    public double GetY2() { return y2; }

    // запись данных
    void SetXY(double nx1, double ny1, double nx2, double ny2)
    {
        x1 = nx1; y1 = ny1;
        x2 = nx2; y2 = ny2;
    }

    // метод, который вычисляет длину линии
    double Length()
    {
        double len;
        len = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
        return len;
    }
}

Нижеследующий программный код демонстрирует создание и использование объектов класса CLine.

public class CTestLine
{
    public static void main(String[] args)
    {
        double x, y; // дополнительные переменные

        // создание объекта класса CLine с помощью конструктора без параметров
        CLine line1 = new CLine();

        // создание объекта класса CLine с помощью конструктора с 4 параметрами
        CLine line2 = new CLine(2.0, 3.0, 4.0, 5.0);

        // использование объектов класса line1
        x = line1.GetX1(); // x = 0.0
        y = line1.GetY2(); // y = 1.0

        // использование объекта класса line2
        x = line2.GetX1(); // x = 2.0
        x = line2.GetX2(); // x = 4.0
        y = line2.GetY2(); // y = 5.0

        // переопределение объекта line1, предшествующий объект будет уничтожен при "сборке" мусора
        line1 = new CLine(-4.0, -2.0, 33.4, -20.5);

        x = line1.GetX1(); // x = -4.0
        y = line1.GetY2(); // y = -20.5
    }
}

Как видно из кода, в функции main() объявляются две ссылки с именами line1, line2 на объекты класса CLine. Для этих ссылок выделяется память с помощью оператора new. Затем, для объекта line2 память снова переопределяется. Старая память будет освобождена при очередной «сборке» мусора.

Пример 2. Создание объекта класса CName, который реализует имя. Функция main() демонстрирует создание объекта класса CName разными способами с помощью разных конструкторов.

// класс, который реализует имя
public class CName
{
    private String name;
    private String surname;
    private String patronymic;

    // конструкторы класса
    // конструктор без параметров
    CName()
    {
        name = surname = patronymic = "";
    }

    // конструктор с тремя параметрами
    CName(String _name, String _surname, String _patronymic)
    {
        name = _name;
        surname = _surname;
        patronymic = _patronymic;
    }

    // методы доступа
    String GetName() { return name; }
    String GetSurname() { return surname; }
    String GetPatronymic() { return patronymic; }

    // функция, которая демонстрирует применение класса CName
    public static void main(String[] args)
    {
        CName nm1 = new CName(); // вызывается конструктор без параметров

        CName nm2; // просто объявление ссылки на объект класса CName, память еще не выделена

        nm2 = new CName("Happy", "New", "Year!"); // создание объекта - выделение памяти

        // проверка
        String str;
        str = nm1.GetName(); // str = ""
        str = nm1.GetSurname(); // str = ""

        str = nm2.GetName(); // str = "Happy"
        str = nm2.GetSurname(); // str = "New"
        str = nm2.GetPatronymic(); // str = "Year!"
    }
}

3. Какие существуют области хранения данных в программах на Java?

В Java для хранения данных (объектов) существует 5 разных хранилищ:

  • регистры. В этом случае данные сохраняются внутри процессора. В регистрах данные обрабатываются быстрее всего. Однако, количество регистров есть строго ограниченным. Компилятор использует регистры по мере необходимости. В Java нет непосредственных команд, чтобы сохранять все данные только в регистрах. Даже в мощных языках C/C++ команды-указания для размещения данных в регистрах носят только рекомендуемый характер;
  • стек. Для программы стек размещается в общей оперативной памяти (RAM). Стек организовывается с использованием указателей стека. Стек работает по принципу LIFO (Last-In-First-Out) – последний пришел, первый вышел. Такая организация есть удобной, когда нужно выделять память для локальных функций (методов) разных уровней вложений. В стеке размещаются только указатели на объекты. Сами объекты размещаются в «куче» (heap). Указатель стека сдвигается вниз, если нужно выделить память, и вверх, если память освобождается. Таким образом, по быстродействию, стек уступает только регистрам. Однако, стек не владеет такой гибкостью как «куча», так как компилятору необходимо знать жизненный цикл данных, размещенных в стеке;
  • «куча». Это есть хранилище общего назначения которое размещается в оперативной памяти (RAM). Здесь сохраняются все объекты (экземпляры объектов) Java. «Куча» есть более гибкой сравнительно со стеком. Это объясняется тем, что компилятор не тратит дополнительных усилий на определение продолжительности существования объектов, которые находятся в «куче». В программе создание объекта происходит с использованием оператора new. В результате выделяется память из «кучи». Однако, выделение памяти памяти из «кучи» занимает больше времени чем в стеке. Следует отметить, что мощные языки C/C++ поддерживают явное создание объектов как в стеке, так и в «куче»;
  • постоянное хранилище. В программах часто используются данные, которые являются неизменными. К таким данным относятся константы (например, строковые константы). Эти данные целесообразно встраивать прямо в код программы. Иногда константы размещаются в постоянной статической памяти (ROM);
  • внешнее хранилище. Внешним хранилищем могут быть постоянные (persistent) носители информации, например, жесткий диск компьютера или носители информации отдаленных компьютеров сети. Этот вид сохранения данных позволяет сохранять объекты на носителях информации, а потом восстанавливать их для сохранения в оперативной памяти.

4. В какой области памяти сохраняются объекты и ссылки на объекты?

Объекты сохраняются в «куче» (heap). Ссылки на объекты сохраняются в стеке.



5. Как в Java создаются и сохраняются массивы объектов?

В отличие от C/C++ массив в Java обязательно инициализируется. Доступ за пределами массива невозможен.
Чтобы создать массив объектов нужно использовать запись наподобие:

ClassName arrayObj[];

или

ClassName[] arrayObj;

где

  • ClassName – имя некоторого класса, который служит типом для массива объектов arrayObj;
  • arrayObj – имя массива объектов.

В вышеприведенном описании объявляется массив ссылок arrayObj на объекты класса ClassName.
Чтобы выделить память для массива arrayObj из 10 элементов типа ClassName, нужно написать:

arrayObj = new ClassName[10];

Это можно сделать другим способом, сразу при объявлении массива:

ClassName arrayObj = new ClassName[10];

Память выделяется только для массива ссылок. Для объектов память еще не выделена. Чтобы выделить память для любого объекта нужно использовать приблизительно следующий код:

for (int i=0; i<arrayObj.length; i++)
{
    arrayObj[i] = new ClassName();
}

В вышеприведенном примере выделяется память для любого объекта в массиве объектов arrayObj. Для определения длины массива используется свойство length, которое есть общедоступным для всех видов массивов в Java.

6. Пример объявления и инициализации массива объектов

Пусть задан класс CLine, реализация которого описывается в п. 2. Пример демонстрирует использование массива из n объектов типа CLine. Значение n задается программно (n = 10).

public class CTestLine
{
    public static void main(String[] args)
    {
        int n = 10;
        CLine[] arrayLines = new CLine[n]; // выделение памяти для массива ссылок

        // выделение памяти для каждого элемента массива
        for (int i=0; i<arrayLines.length; i++)
        {
            // выделение памяти и инициализация каждого отдельного элемента массива
            arrayLines[i] = new CLine(i*2, i*1.5, i+2.2, i-1);
        }

        // использование массива, вычисление суммарной длины всех отрезков
        double sumLength = 0;
        for (int i=0; i<arrayLines.length; i++)
            sumLength+=arrayLines[i].Length();

        System.out.println("Sum = " + sumLength); // Sum = 45.45345204172149
    }
}


Связанные темы