Как сделать конструктор копирования java

Добавил пользователь Алексей Ф.
Обновлено: 05.10.2024

В классе на основе объектно-ориентированного программирования , конструктор (аббревиатура: т е р ) представляет собой особый тип подпрограммы призваны создать объект . Он подготавливает новый объект к использованию, часто принимая аргументы, которые конструктор использует для установки требуемых переменных-членов .

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

Большинство языков допускают перегрузку конструктора, поскольку для класса может быть несколько конструкторов с разными параметрами. Некоторые языки учитывают некоторые особые типы конструкторов. Конструкторы, которые конкретно используют один класс для создания объектов и возврата нового экземпляра класса, абстрагируются фабриками , которые также создают объекты, но могут делать это различными способами, используя несколько классов или разные схемы распределения, такие как пул объектов .

Содержание

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

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

В C ++ конструкторы перемещения принимают ссылку на значение объекта класса и используются для реализации передачи владения ресурсами объекта параметра.

В C ++ объекты создаются в стеке, когда конструктор вызывается без оператора new, и создаются в куче, когда конструктор вызывается с оператором new. Объекты стека удаляются неявно, когда они выходят за пределы области видимости, в то время как объекты кучи должны удаляться неявно деструктором или явно с помощью оператора удаления .

В Java конструкторы отличаются от других методов тем, что:

Конструкторы Java выполняют следующие задачи в следующем порядке:

  1. Вызовите конструктор суперкласса по умолчанию, если конструктор не определен.
  2. Инициализируйте переменные-члены указанными значениями.
  3. Выполняет тело конструктора.

Java разрешает пользователям вызывать один конструктор в другом конструкторе с помощью this() ключевого слова. Но this() должно быть первое заявление. [3]

Java предоставляет доступ к конструктору суперкласса через super ключевое слово.

Конструктор, принимающий нулевое количество аргументов, называется конструктором без аргументов или без аргументов. [4]

Начиная с ES6, в JavaScript есть прямые конструкторы, как и во многих других языках программирования. Они написаны как таковые

Это может быть создано как таковое

Эквивалентом этого до ES6 было создание функции, которая создает экземпляр объекта как такового.

Это создается так же, как указано выше.

В Visual Basic .NET конструкторы используют объявление метода с именем " New ".

Статические конструкторы позволяют инициализировать сложную статическую переменную. [7] Статические конструкторы вызываются неявно при первом обращении к классу. Любой вызов класса (статический вызов или вызов конструктора) запускает выполнение статического конструктора. Статические конструкторы являются потокобезопасными и реализуют одноэлементный шаблон . При использовании в универсальном классе программирования статические конструкторы вызываются при каждом новом создании универсального экземпляра, по одному для каждого типа. Также создаются статические переменные.

В C ++ имя конструктора - это имя класса. Он ничего не возвращает. У него могут быть параметры, как у любой функции-члена . Функции конструктора обычно объявляются в общедоступном разделе, но также могут быть объявлены в защищенном и закрытом разделах, если пользователь хочет ограничить доступ к ним.

Конструктор состоит из двух частей. Сначала это список инициализаторов, который следует за списком параметров и перед телом метода. Он начинается с двоеточия, а записи разделяются запятыми. Список инициализаторов не требуется, но дает возможность предоставлять значения для элементов данных и избегать отдельных операторов присваивания. Список инициализаторов требуется, если у вас есть члены данных константного или ссылочного типа или члены, не имеющие логики конструктора без параметров. Присваивания выполняются в соответствии с порядком, в котором объявлены элементы данных (даже если порядок в списке инициализаторов отличается). [8] Вторая часть - это тело, которое представляет собой обычное тело метода, заключенное в фигурные скобки.

C ++ позволяет использовать более одного конструктора. Остальные конструкторы должны иметь другие параметры. Кроме того, конструкторы, которые содержат параметры, которым заданы значения по умолчанию, должны придерживаться ограничения, согласно которому не всем параметрам присваиваются значения по умолчанию. Это ситуация, которая имеет значение только при наличии конструктора по умолчанию. Конструктор базового класса (или базовых классов) также может вызываться производным классом. Функции-конструкторы не наследуются, и на их адреса нельзя ссылаться. Когда требуется выделение памяти, неявно вызываются операторы new и delete .

Конструктор копирования имеет параметр того же типа, который передается как ссылка на константу , например Vector (const Vector & rhs) . Если он не указан явно, компилятор использует конструктор копирования для каждой переменной-члена или просто копирует значения в случае примитивных типов. Реализация по умолчанию неэффективна, если класс имеет динамически выделяемые члены (или дескрипторы для других ресурсов), потому что это может привести к двойным вызовам удаления (или двойному освобождению ресурсов) при уничтожении.

При возврате объектов из функций или передаче объектов по значению конструктор копирования объектов будет вызываться неявно, если не применяется оптимизация возвращаемого значения .

C ++ неявно генерирует конструктор копирования по умолчанию, который будет вызывать конструкторы копирования для всех базовых классов и всех переменных-членов, если программист не предоставит один, явно удаляет конструктор копирования (для предотвращения клонирования) или один из базовых классов или конструктор копирования переменных-членов удаляется или недоступен (частный). В большинстве случаев, требующих настраиваемого конструктора копирования (например, подсчета ссылок , глубокого копирования указателей), также требуется настройка деструктора и оператора присваивания копии . Это обычно называют Правилом трех .

В Eiffel процедуры инициализации новых объектов называются процедурами создания . Процедуры создания имеют следующие особенности:

  • Процедуры создания не имеют явного типа возврата (по определению процедуры ). [а]
  • Названы процедуры создания.
  • Процедуры создания обозначаются по имени как процедуры создания в тексте класса.
  • Процедуры создания могут быть явно вызваны для повторной инициализации существующих объектов.
  • Каждый эффективный (т. Е. Конкретный или не абстрактный) класс должен обозначать как минимум одну процедуру создания.
  • Процедуры создания должны оставлять вновь инициализированный объект в состоянии, удовлетворяющем инварианту класса. [b]

Хотя создание объекта связано с некоторыми тонкостями, [9] создание атрибута с типичным объявлением, x: T выраженным в инструкции создания, create x.make состоит из следующей последовательности шагов:

  • Создайте новый прямой экземпляр типа T . [c]
  • Выполните процедуру создания make для вновь созданного экземпляра.
  • Присоедините вновь инициализированный объект к сущности x .

В первом фрагменте ниже POINT определен класс . Процедура make кодируется после ключевого слова feature .

Ключевое слово create вводит список процедур, которые можно использовать для инициализации экземпляров. В этом случае список включает default_create процедуру с пустой реализацией, унаследованной от класса ANY , и make процедуру, закодированную внутри класса.

Во втором фрагменте класс, который является клиентом, POINT имеет объявления my_point_1 и my_point_2 тип POINT .

В процедурном коде my_point_1 создается как источник (0,0, 0,0). Поскольку процедура создания не указана, используется процедура, default_create унаследованная от класса ANY . Эта строка могла быть закодирована create my_point_1.default_create . В инструкции с create ключевым словом могут использоваться только процедуры, названные как процедуры создания . Далее идет инструкция по созданию my_point_2 , предоставляющая начальные значения для my_point_2 координат. Третья инструкция выполняет обычный вызов экземпляра make процедуры для повторной инициализации экземпляра, к которому присоединены my_point_2 другие значения.

CFML использует метод с именем " init " как метод конструктора.

Создайте экземпляр сыра.

Начиная с ColdFusion 10, [10] CFML также поддерживает указание имени метода конструктора:

В Object Pascal конструктор похож на фабричный метод . Единственное синтаксическое отличие от обычных методов - это ключевое слово constructor перед именем (вместо procedure или function ). Он может иметь любое имя, хотя по соглашению в Create качестве префикса используется, например, in CreateWithFormatting . Создание экземпляра класса работает как вызов статического метода класса: TPerson.Create('Peter') .

В языке программирования Perl версии 5 по умолчанию конструкторы являются фабричными методами , то есть методами, которые создают и возвращают объект, что конкретно означает создание и возврат благословенной ссылки. Типичный объект - это ссылка на хэш, хотя ссылки на другие типы также используются редко. По соглашению единственный конструктор называется новым , хотя ему разрешено называть его иначе или иметь несколько конструкторов. Например, класс Person может иметь конструктор с именем new, а также конструктор new_from_file, который считывает файл для атрибутов Person, и new_from_person, который использует другой объект Person в качестве шаблона.

В объектной системе Moose для Perl большую часть этого шаблона можно исключить, создать новый по умолчанию , можно указать атрибуты, а также указать, можно ли их устанавливать, сбрасывать или требовать. Кроме того, любые дополнительные функции конструктора могут быть включены в метод BUILD, который сгенерированный конструктор Moose вызовет после проверки аргументов. Можно указать метод BUILDARGS для обработки аргументов конструктора не в форме hashref / key => value.

В обоих случаях класс Person создается следующим образом:

С Ракой , еще более шаблонным может быть опущено, если учесть , что по умолчанию новый метод наследуется, атрибуты могут быть определены, а также могут ли они быть установлены, сброшены, или требуются. Кроме того, любые дополнительные функции конструктора могут быть включены в метод BUILD, который будет вызываться для обеспечения возможности индивидуальной инициализации. TWEAK , метод может быть определен , чтобы после процесса любые атрибуты уже (неявно) инициализируется.

Класс Person создается следующим образом:

В качестве альтернативы именованные параметры могут быть указаны с использованием синтаксиса пары двоеточий в Perl 6:

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

В Python , конструкторы определяются одним или обоими __new__ и __init__ методов. Новый экземпляр создается путем вызова класса , как если бы это была функция, которая вызывает __new__ и __init__ методы. Если метод конструктора не определен в классе, будет вызван следующий метод, найденный в порядке разрешения метода класса . [11]

В типичном случае __init__ необходимо определить только метод. (Наиболее частое исключение - неизменяемые объекты.)

Классы обычно действуют как фабрики для новых экземпляров самих себя, то есть класс - это вызываемый объект (например, функция), при этом вызов является конструктором, а вызов класса возвращает экземпляр этого класса. Однако __new__ методу разрешено возвращать что-то другое, кроме экземпляра класса для специализированных целей. В этом случае __init__ не вызывается. [12]

В Ruby конструкторы создаются путем определения вызываемого метода initialize . Этот метод выполняется для инициализации каждого нового экземпляра.

В OCaml есть один конструктор. Параметры определяются сразу после имени класса. Они могут использоваться для инициализации переменных экземпляра и доступны во всем классе. Вызываемый анонимный скрытый метод initializer позволяет вычислить выражение сразу после того, как объект был построен. [13]

Я проходил через Copy Constructors, я прошел через ссылки в стеке над потоком и другими. Но я не понимаю следующие моменты.

  • Зачем нам нужен конструктор копирования
  • Когда нам понадобится Копировать конструктор

Я имею в виду, что такое точная ситуация или сценарий, который нам нужен для использования Copy Constructor. Может ли кто-нибудь объяснить с помощью примера или указать ссылки, чтобы я мог разобраться и понять их в понятном виде.

Ниже приведены ссылки, которые я прочитал, чтобы понять, что такое конструктор копирования.

Вторая ссылка объясняет "почему" и "where" используется конструктор копирования. Но я все еще не понимаю.

Ниже мой класс Employee.java

Copy Constructor используется для создания и точной копии объекта с теми же значениями существующего объекта.

Скажем, например, у нас есть Сотрудник со значениями как rollNo: 1 и name: avinash . Copy Constructor создаст аналогичный объект со значениями rollNo: 1 и name: avinash . Но оба они являются двумя разными объектами, а изменения значений объекта не влияют на другой объект.

Если у нас есть такой конструктор, как

для создания объекта. Мы можем вызвать тот же конструктор для создания другого объекта. Но почему нам нужно вызвать конструктор копирования. Когда нам нужно его называть? Пожалуйста, объясните

Есть две веские причины для использования конструктора копирования вместо конструктора, передающего все параметры:

  1. когда у вас есть сложный объект со многими атрибутами, гораздо проще использовать конструктор копирования
  2. если вы добавляете атрибут в свой класс, вы просто изменяете конструктор копирования, чтобы учитывать этот новый атрибут вместо того, чтобы изменять каждое появление другого конструктора

Конструкторы копирования, по договоренности, должны обеспечивать глубокую копию объектов. Как уже упоминалось в других ответах, основное удобство, предоставляемое конструкторами копирования, - это когда ваш объект становится слишком сложным. Обратите внимание, что java.lang.Cloneable предоставляет (почти) аналогичное объявление.

Но для использования конструкторов копирования в интерфейсе Cloneable существует ряд преимуществ.

Cloneable , поскольку интерфейс фактически не предоставляет никаких методов. Чтобы он был эффективным, вам все равно нужно переопределить метод clone java.lang.Object . Это довольно противоречивое использование для интерфейса.

clone возвращает Object . Для того, чтобы это было полезно, вам все равно нужно придумать. Это неудобно и может привести к ошибкам во время выполнения.

Метод clone плохо документирован. Для clone все может быть испорчено, если у вас есть конечные поля, указывающие на изменяемые объекты.

Самое главное, что конструкторы копирования могут принимать и копировать экземпляры подклассов. IMO, здесь действительно сияют конструкторы копирования.

Есть больше преимуществ (см. Joshua Bloch Effective Java 2e), но это те моменты, которые я нашел наиболее подходящими для того, над чем я работал до сих пор.

[1] Ничто в языке Java фактически не предоставляет конструкцию по умолчанию для глубокого копирования. В большинстве случаев объекты могут просто сказать программистам, что они могут быть глубоко скопированы, например, путем реализации Cloneable или предоставления конструктора копии.

конструкторы Java_vertex

Конструкторы - это специальные методы, которые вызывается при создании объекта . Они "конструируют" новый объект определенного класса.

Шаг за шагом

Итак, чтобы объяснить нагляднее, представим, как работает программа.

1. Вы создаете основное "тело" программы, прописывая метод main:

2. Допустим, Вам нужен объект класса Cat. Класс Cat у вас уже есть, и выглядит он так:

Вы пишете строку, которая должна создать объект класса Cat:

3. В тот момент, когда программа приступает к созданию объекта cat1, она идет в class Cat:


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


Но в нашем классе есть только геттеры и сеттеры - никаких конструкторов! Что же делать? Теперь объект не создастся?

Создастся, конечно. А все потому, что по-настоящему конструктор все равно присутствует - просто он явно не указан. Теперь, давайте посмотрим как создавать конструкторы явно, и какими они вообще бывают.

Явные и неявные конструкторы

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

Преимущество 1. Контроль над вводом данных.

Сначала, дайте посмотрим на изображение. Какие отличия Вы видите?

конструкторы Java_vertex

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

конструкторы Java_vertex

Явно прописывая конструктор, Вы получаете возможность регулировать, какие параметры и в каком количестве нужно задать для создания объекта определенного класса.

Код№1 - класс Cat - скорее всего, был создан с использованием неявного конструктора. Он не просит никаких параметров.

Код№2 - класс Scanner - уже использует явно описанный конструктор. Он требует один параметр - и без него создать объект невозможно.

Код№3 - класс Dog - тоже использует явно описанный конструктор. Но тут, как мы видим, требуется уже три параметра - имя ("Шарик"), порода ("мопс") и возраст собаки (2 года).

Преимущество 2. Меньше строчек кода.

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

Java-конструктор – это специальный метод, который вызывается при создании экземпляра объекта. Другими словами, когда вы используете новое ключевое слово. Цель конструктора – инициализировать вновь созданный объект перед его использованием.

Вот простой пример:

Здесь создается новый объект MyClass и вызывается конструктор без аргументов MyClass.

Конструктор класса инициализирует экземпляры (объекты) этого класса. Обычно конструктор инициализирует поля объекта, которые необходимо инициализировать. Конструкторы также могут принимать параметры, поэтому поля могут быть инициализированы в объекте во время создания.

Объявление конструктора Java

Простой пример объявления конструктора:

Конструктор – это часть:

Перегрузка конструктора

Класс может иметь несколько конструкторов, если их сигнатура (параметры, которые они принимают) не совпадают. Когда класс содержит несколько конструкторов, мы говорим, что конструктор перегружен (поставляется в нескольких версиях):

Класс выше содержит два конструктора. Первый – без аргументов, то есть он не принимает параметров. Второй – принимает параметр int. Внутри тела значение параметра int присваивается полю, то есть значение параметра копируется в поле. Таким образом, поле инициализируется для данного значения параметра.

Ключевое слово this перед именем поля (this.number) необязательно. Оно просто сообщает компилятору, что это поле с именем number, на которое ссылаются.

Конструктор по умолчанию, без аргументов

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

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

Параметры

Конструктор может принимать параметры, которые потом используются для инициализации внутреннего состояния (полей) вновь созданного объекта:

В этом примере объявлены 3 параметра: первый, последний и год. Внутри тела значения этих трех параметров присваиваются полям объекта Employee.

Разрывы строки на Java после каждого параметра являются необязательными. Компилятор здесь игнорирует разрывы строк. Вы также можете написать объявление параметра в одну строку, если хотите, например:

Чтобы вызвать этот конструктор, который принимает три параметра, вы должны создать экземпляр объекта Employee следующим образом:

Параметры передаются конструктору в скобках после имени класса справа от знака равенства. Затем объект создается, и конструктор выполняется. После выполнения описанного выше конструктора поля, инициализированные им, будут иметь значения параметров, передаваемых ему.

Внутри конструктора класса Employee идентификаторы firstName, lastName и birthYear теперь ссылаются на параметры конструктора, а не на поля Employee с одинаковыми именами. Таким образом, конструктор теперь просто устанавливает параметры, равные им самим. Поля Сотрудника никогда не инициализируются.

Чтобы сообщить компилятору, что вы имеете в виду поля класса Employee, а не параметры, поместите ключевое слово this и точку перед именем поля:

Теперь поля Employee правильно инициализируются внутри конструктора.

Вызов

Вы вызываете конструктор, когда создаете новый экземпляр класса, содержащий его:

Этот пример вызывает конструктор без аргументов для MyClass, как определено ранее в этом тексте.

Если вы хотите передать параметры конструктору, вы должны включить их в круглые скобки после имени класса:

Этот пример передает один параметр конструктору MyClass, который принимает int в качестве параметра.

Вызов конструктора из конструктора

В Java можно вызвать конструктор из другого конструктора. Для этого используется ключевое слово this:

Обратите внимание на второе определение конструктора. Внутри тела конструктора вы найдете этот оператор Java:

Ключевое слово this, за которым следуют скобки и параметры, означает, что вызывается другой конструктор в том же классе. Какой другой вызываемый конструктор зависит от того, какие параметры вы передаете в вызов конструктора (в скобках после ключевого слова this). В этом примере это первый конструктор в классе, который вызывается.

Вызов в суперклассах

Класс, который расширяет другой, не наследует его конструкторы. Однако подкласс должен вызывать конструктор в суперклассе внутри одного из конструкторов подкласса!

Класс Car расширяет (наследует) класс Vehicle:

Обратите внимание на конструктор в классе Car. Он вызывает конструктор в суперклассе, используя этот оператор:

Использование ключевого слова super относится к суперклассу класса. Когда за ключевым словом следуют круглые скобки, как здесь, это относится к конструктору в суперклассе. В этом случае это относится к конструктору в классе Vehicle. Поскольку Car расширяет Vehicle, все конструкторы Car должен вызывать конструктор в Vehicle.

Модификаторы доступа

Модификатор доступа конструктора определяет, какие классы в вашем приложении могут вызывать его. Например, если конструктор объявлен защищенным, то он может вызывать только классы в одном пакете или подклассы этого класса.

Класс может иметь несколько конструкторов, а каждый конструктор свой собственный модификатор доступа. Таким образом, некоторые конструкторы могут быть доступны для всех классов в вашем приложении, в то время как другие конструкторы доступны только для классов в том же пакете, подклассах или даже только для самого класса (частные конструкторы).

Исключение

Можно сгенерировать исключение из конструктора:

Обратите внимание на исключительную часть throws объявления конструктора. Она объявляет, что конструктор может выдать исключение. Если это произойдет, созданный экземпляр Car недействителен.

Вот пример вызова конструктора Car:

Если из конструктора Car выдается исключение, переменной car никогда не будет назначена ссылка на объект Car, который вы пытаетесь создать. Переменная car по-прежнему будет указывать на ноль.

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

Читайте также: