4. Создание объектов. Конструктор.
Last updated
Was this helpful?
Last updated
Was this helpful?
Когда мы объявляем новый класс, то мы фактически создаем новый тип данных, который можно использовать для объявления объектов данного типа. Создание объектов класса представляет собой двухэтапный процесс. Сначала следует объявить переменную типа класса.
Эта переменная является ссылочной, то есть она не содержит объект, а ссылается на него (примерно как указатель в C не содержит значение, а содержит адрес, то есть переменная ссылается на значение в памяти).
Затем нужно создать конкретный физический объект и получить на него ссылку. Эти операции выполняются с помощью оператора new
. Этот оператор динамически (то есть, во время выполнения программы) резервирует память для объекта, инициирует процесс создания объекта и возвращает ссылку на него (ссылка представляет собой адрес объекта в памяти). Далее нам необходимо сохранить ссылку в переменной.
В первой строке переменная mybox
объявляется как ссылка на объект типа Box
. В данный момент mybox пока еще не ссылается на конкретный объект, значение переменной равно null
. В следующей строке кода выделяется память для конкретного объекта, а переменной mybox
присваивается ссылка на этот объект.
После выполнения второй строки кода переменную mybox можно использовать так, как если бы она была объектом типа Box
. Но в действительности переменная mybox
просто содержит адрес памяти конкретного объекта типа Box
. Результат выполнения этих двух строк кода показан на рисунке 4.3.
Какие действия выполняет приведенный ниже фрагмент кода?
На первый взгляд, переменной b2
присваивается ссылка на копию объекта, на которую ссылается переменная b1
. Таким образом, может показаться, что переменные b1
и b2
ссылаются на совершенно разные объекты, но это не так. После выполнения данного фрагмента кода обе переменные, b1
и b2
, будут ссылаться на один и тот же объект. Таким образом, любые изменения, внесенные в объекте по ссылке в переменную b2
, окажут влияние на объект, на который ссылается переменная b1
, поскольку это один и тот же объект (рис. 4.4)
В общем случае, для передачи аргументов подпрограмме (в данном случае, методу) в языках программирования имеются два способа.
Первым способом является передача по значению. В этом случае значение аргумента копируется в параметр метода. Следовательно, изменения, вносимые в параметр метода, не оказывают никакого влияния на аргумент.
Вторым способом является передача по ссылке. В этом случае параметру передается ссылка на значение аргумента. Изменения, вносимые в параметр метода, будет оказывать влияние на аргумент, используемый при вызове.
Все аргументы в Java передаются по значению, но конкретный результат зависит от того, какой именно тип данных передается: примитивный или ссылочный.
Когда методу передается аргумент примитивного типа, его передача происходит по значению. В итоге создается копия аргумента, и все, что происходит с параметром, принимающим этот аргумент, не оказывает никакого влияния за пределами вызываемого метода.
При передаче объекта в качестве аргумента методу ситуация меняется коренным образом, поскольку объекты, по существу, передаются при вызове по ссылке. Не следует, однако , забывать, что при объявлении переменной типа класса создается лишь ссылка на объект этого класса. Таким образом, при передаче этой ссылки методу принимающий ее параметр будет ссылаться на тот же самый объект, на который ссылается и аргумент. По существу, это означает, что объекты действуют так, как будто они передаются методам по ссылке. Но изменения объекта в теле метода оказывают влияние на объект, указываемый в качестве аргумента.
Основной причиной чрезмерных затрат в программировании является "небезопасное" программирование.
Основные проблемы с безопасностью относятся к инициализации и завершению. Очень многие ошибки при программировании на языке C обусловлены неверной инициализацией переменных. Это особенно часто происходит при работе с библиотеками, когда пользователи не знают, как нужно инициализировать компонент библиотеки или забывают это сделать.
В языке C++ впервые появляется понятие конструктора - специального метода, который вызывается при создании нового объекта.
В Java разработчик класса может в обязательном порядке выполнить инициализацию каждого объекта при помощи специального метода, называемого конструктором. Если у класса имеется конструктор, Java автоматически вызывает его при создании объекта, перед тем как пользователи смогут обратиться к этому объекту. Таким образом, инициализация объекта гарантирована.
Синтаксис конструктора отличается от синтаксиса обычного метода. Его имя совпадает с именем класса, в котором он находится, и он не имеет возвращаемого типа.
Как было сказано выше, оператор new
динамически выделяет оперативную память для создания объекта. Общая форма использования оператора new
выглядит следующим образом
Имя класса, за которым следуют круглые скобки, обозначает конструктор данного класса. Конструкторы являются важной частью всех классов и обладают множеством важных свойств В большинстве классов, используемых в реальных программах, явно объявляются свои конструкторы в пределах определения класса
Инициализация всех переменных класса при каждом создании объекта – занятие довольно утомительное. В связи с этим, в Java разрешается выполнять собственную инициализацию при создании объектов. Такая инициализация осуществляется с помощью конструктора.
Еще раз обратите внимание, что имя конструктора совпадает с именем класса, в котором он находится, а синтаксис аналогичен синтаксису метода. Также конструктор не имеет возвращаемого типа - даже типа void
.
Теперь нам должно быть понятно, почему при создании нового объекта, после имени класса требуется указывать круглые скобки. В действительности оператор new
вызывает конструктор класса.
Оператор new
вызывает конструктор Box()
. Но мы ранее не создавали этот конструктор, почему компилятор не выдал ошибку, когда мы запускали приложение?
Конструктор не получающий аргументов, называется конструктором по умолчанию (в документации Java он называется конструктор без аргументов).
Конструктор по умолчанию инициализирует все переменные экземпляра устанавливаемыми по умолчанию значениями, которые могут быть нулевыми, пустыми (null) и логическими (false) для числовых, ссылочных и логических типов соответственно. Зачастую конструктора по умолчанию оказывается достаточно для простых классов. Если же вы определите в классе хотя бы один конструктор, то конструктор по умолчанию создан не будет. Именно поэтому, следующий код выдаст ошибку.
Представим, что у нас есть два объекта одного класса и для этих двух объектов вызывается один и тот же метод:
Если существует один метод getArea()
, как метод узнает, для какого объекта он вызывается – для box_1
или дляbox_2
?
Оказывается, при вызове метода getArea()
(как и при вызове любого другого метода) передается скрытый первый аргумент – ссылка на используемый объект. Таким образом, вызовы методов на самом деле выглядят так:
Передача дополнительного аргумента относится к внутреннему синтаксису. При попытке явно воспользоваться ею компилятор выдаст сообщение об ошибке.
Предположим, во время выполнения метода нам необходимо получить ссылку на текущий объект. Так как эта ссылка передается компилятором скрытно, идентификатора для нее не существует. Но для решения этой задачи существует ключевое слово this
.
Обращаться с ней можно точно так же, как и с любой другой ссылкой на объект. Для вызова метода класса из другого метода этого же класса, использовать ключевое слово this
не нужно.
Ключевое слово this
чаще всего используется в ситуации, когда локальная переменная скрывает поле класса. В Java не допускается объявление двух локальных переменных с одним и тем же именем в той же самой области действия. Однако, мы можем объявить локальные переменные, имена которых совпадают с именами полей класса.
Когда имя локальной переменной совпадает с именем переменной экземпляра, локальная переменная скрывает поле класса.
Можно решить эту ситуацию путем изменения имен локальных переменных, но это некорректно с точки зрения хорошего стиля написания кода. Грамотным решением является использование ключевого слова this
. Это позволит переменным иметь одинаковые названия, а к переменным экземпляра можно будет обратиться с помощью этого ключевого слова.
Иногда, во время выполнения метода необходимо получить ссылку на текущий объект, для которого был вызван метод. Так как ссылка на него передается скрытно, идентификатора для нее нет. Но для этого существует специальное ключевое слово – this
. Ключевое слово this
предоставляет ссылку на объект, для которого был вызван метод. Обращаться с ней можно как и с любой другой ссылкой на объект.