Что делает оператор new java
Перейти к содержимому

Что делает оператор new java

  • автор:

Оператор new

Оператор (операторная функция) new создаёт экземпляр объекта, встроенного или определённого пользователем, имеющего конструктор.

Синтаксис

new constructor[([arguments])]

Параметры

Функция, задающая тип объекта.

Список параметров, с которыми будет вызван конструктор.

Описание

Создание объекта, определённого пользователем, требует два шага:

  1. Написать функцию, которая задаст тип объекта.
  2. Создать экземпляр объекта, используя new .

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

Когда исполняется new Foo(. ) , происходит следующее:

  1. Создаётся новый объект, наследующий Foo.prototype.
  2. Вызывается конструктор — функция Foo с указанными аргументами и this , привязанным к только что созданному объекту. new Foo эквивалентно new Foo() , то есть если аргументы не указаны, Foo вызывается без аргументов.
  3. Результатом выражения new становится объект, возвращённый конструктором. Если конструктор не возвращает объект явно, используется объект из п. 1. (Обычно конструкторы не возвращают значение, но они могут делать это, если нужно переопределить обычный процесс создания объектов.)

Всегда можно добавить свойство к уже созданному объекту. Например, car1.color = «black» добавляет свойство color к объекту car1 , и присваивает ему значение » black «. Это не затрагивает другие объекты. Чтобы добавить свойство ко всем объектам типа, нужно добавлять его в определение типа Car.

Добавить свойство к ранее определённому типу можно используя свойство Function.prototype (en-US) . Это определит свойство для всех объектов, созданных этой функцией, а не только у какого-либо экземпляра. Следующий пример добавляет свойство color со значением null всем объектам типа car , а потом меняет его на » black » только у экземпляра car1 . Больше информации в статье prototype (en-US) .

function Car() > car1 = new Car(); console.log(car1.color); // undefined Car.prototype.color = null; console.log(car1.color); // null car1.color = "black"; console.log(car1.color); // black 

Примеры

Тип объекта и экземпляры объекта

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

function Car(make, model, year)  this.make = make; this.model = model; this.year = year; > 

Теперь можно создать экземпляр типа car:

var mycar = new Car("Eagle", "Talon TSi", 1993); 

Это выражение создаёт экземпляр mycar и присваивает его свойствам указанные значения. Таким образом, mycar.make принимает значение «Eagle», mycar.year принимает значение 1993, и так далее.

Можно создать любое количество экземпляров car с помощью оператора new . Например:

var kenscar = new Car("Nissan", "300ZX", 1992); 

Объект в качестве свойства

Предположим, есть объект person :

function Person(name, age, sex)  this.name = name; this.age = age; this.sex = sex; > 

Создадим два экземпляра:

var rand = new Person("Rand McNally", 33, "M"); var ken = new Person("Ken Jones", 39, "M"); 

Изменим определение car , добавив свойство, указывающее владельца — owner :

function Car(make, model, year, owner)  this.make = make; this.model = model; this.year = year; this.owner = owner; > 

Создадим экземпляры car:

var car1 = new Car("Eagle", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken); 

Вместо строковых или численных значений можно передать объект как параметр. Чтобы узнать имя владельца car2 , получим доступ к свойству:

.owner.name; 

Спецификации

Specification
ECMAScript Language Specification
# sec-new-operator

Совместимость с браузерами

BCD tables only load in the browser

Смотрите также

  • Function
  • Reflect.construct()

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 7 авг. 2023 г. by MDN contributors.

Your blueprint for a better internet.

MDN

Support

  • Product help
  • Report an issue

Our communities

Developers

  • Web Technologies
  • Learn Web Development
  • MDN Plus
  • Hacks Blog
  • Website Privacy Notice
  • Cookies
  • Legal
  • Community Participation Guidelines

Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998– 2024 by individual mozilla.org contributors. Content available under a Creative Commons license.

Конструктор. Ключевое слово new.

Объекты в Java создаются с помощью зарезервированного слова new, после которого идет конструктор – специальный метод, занимающаяся созданием объекта и инициализацией полей создаваемого объекта. Для него не указывается тип возвращаемого значения, и он не является ни методом объекта (вызывается через имя класса когда объекта еще нет), ни методом класса (в конструкторе доступен объект и его поля через ссылку this ). На самом деле конструктор в сочетании с оператором new возвращает ссылку на создаваемый объект и может считаться особым видом методов, соединяющим в себе черты методов класса и методов объекта.

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

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

Если же идет наследование от класса в котором уже имеется конструктор (пусть даже и конструктор по умолчанию), возникает некоторая специфика. Первым оператором в конструкторе должен быть вызов конструктора из суперкласса. Но его делают не через имя этого класса, а с помощью зарезервированного слова super (от «superclass»), после которого идет необходимый для прародительского конструктора список параметров. Этот конструктор инициализирует поля данных, которые наследуются от суперкласса (в том числе и от всех более ранних прародителей).

Конструктор, оператор «new»

Обычный синтаксис <. >позволяет создать только один объект. Но зачастую нам нужно создать множество похожих, однотипных объектов, таких как пользователи, элементы меню и так далее.

Это можно сделать при помощи функции-конструктора и оператора «new» .

Функция-конструктор

Функции-конструкторы технически являются обычными функциями. Но есть два соглашения:

  1. Имя функции-конструктора должно начинаться с большой буквы.
  2. Функция-конструктор должна выполняться только с помощью оператора «new» .
function User(name) < this.name = name; this.isAdmin = false; >let user = new User("Jack"); alert(user.name); // Jack alert(user.isAdmin); // false

Когда функция вызывается как new User(. ) , происходит следующее:

  1. Создаётся новый пустой объект, и он присваивается this .
  2. Выполняется тело функции. Обычно оно модифицирует this , добавляя туда новые свойства.
  3. Возвращается значение this .

Другими словами, new User(. ) делает что-то вроде:

function User(name) < // this = <>; (неявно) // добавляет свойства к this this.name = name; this.isAdmin = false; // return this; (неявно) >

Таким образом, let user = new User(«Jack») возвращает тот же результат, что и:

let user = < name: "Jack", isAdmin: false >;

Теперь, если нам будет необходимо создать других пользователей, мы можем просто вызвать new User(«Ann») , new User(«Alice») и так далее. Данная конструкция гораздо удобнее и читабельнее, чем многократное создание литерала объекта.

Это и является основной целью конструкторов – реализовать код для многократного создания однотипных объектов.

Давайте ещё раз отметим – технически любая функция (кроме стрелочных функций, поскольку у них нет this ) может использоваться в качестве конструктора. Его можно запустить с помощью new , и он выполнит выше указанный алгоритм. Подобные функции должны начинаться с заглавной буквы – это общепринятое соглашение, чтобы было ясно, что функция должна вызываться с помощью «new».

new function() < … >

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

// создаём функцию и сразу же вызываем её с помощью new let user = new function() < this.name = "John"; this.isAdmin = false; // . другой код для создания пользователя // возможна любая сложная логика и инструкции // локальные переменные и так далее >;

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

Проверка на вызов в режиме конструктора: new.target

Продвинутая возможность

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

Используя специальное свойство new.target внутри функции, мы можем проверить, вызвана ли функция при помощи оператора new или без него.

В случае обычного вызова функции new.target будет undefined . Если же она была вызвана при помощи new , new.target будет равен самой функции.

function User() < alert(new.target); >// без "new": User(); // undefined // с "new": new User(); // function User

Это можно использовать внутри функции, чтобы узнать, была ли она вызвана при помощи new , «в режиме конструктора», или без него, «в обычном режиме».

Также мы можем сделать, чтобы вызовы с new и без него делали одно и то же:

function User(name) < if (!new.target) < // в случае, если вы вызвали меня без оператора new return new User(name); // . я добавлю new за вас >this.name = name; > let john = User("John"); // переадресовывает вызов на new User alert(john.name); // John

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

Впрочем, вероятно, это не очень хорошая практика использовать этот трюк везде, так как отсутствие new может ввести разработчика в заблуждение. С new мы точно знаем, что создаётся новый объект.

Возврат значения из конструктора, return

Обычно конструкторы не имеют оператора return . Их задача – записать все необходимое в this , и это автоматически становится результатом.

Но если return всё же есть, то применяется простое правило:

  • При вызове return с объектом, вместо this вернётся объект.
  • При вызове return с примитивным значением, оно проигнорируется.

Другими словами, return с объектом возвращает этот объект, во всех остальных случаях возвращается this .

К примеру, здесь return замещает this , возвращая объект:

function BigUser() < this.name = "John"; return < name: "Godzilla" >; // alert( new BigUser().name ); // Godzilla, получили этот объект

А вот пример с пустым return (или мы могли бы поставить примитив после return , неважно):

function SmallUser() < this.name = "John"; return; // alert( new SmallUser().name ); // John

Обычно у конструкторов отсутствует return . Здесь мы упомянули особое поведение с возвращаемыми объектами в основном для полноты картины.

Пропуск скобок

Кстати, мы можем не ставить круглые скобки после new :

let user = new User; // 

Пропуск скобок считается плохой практикой, но просто чтобы вы знали, такой синтаксис разрешён спецификацией.

Создание методов в конструкторе

Использование конструкторов для создания объектов даёт большую гибкость. Функции-конструкторы могут иметь параметры, определяющие, как создавать объект и что в него записывать.

Конечно, мы можем добавить к this не только свойства, но и методы.

Например, new User(name) ниже создаёт объект с заданным name и методом sayHi :

function User(name) < this.name = name; this.sayHi = function() < alert( "Меня зовут: " + this.name ); >; > let john = new User("John"); john.sayHi(); // Меня зовут: John /* john = < name: "John", sayHi: function() < . >> */

Для создания сложных объектов есть и более продвинутый синтаксис – классы, который мы рассмотрим позже.

Итого

  • Функции-конструкторы или просто конструкторы, являются обычными функциями, но существует общепринятое соглашение именовать их с заглавной буквы.
  • Функции-конструкторы следует вызывать только с помощью new . Такой вызов подразумевает создание пустого this в начале и возврат заполненного в конце.

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

JavaScript предоставляет функции-конструкторы для множества встроенных объектов языка: таких как Date , Set , и других, которые нам ещё предстоит изучить.

Мы ещё вернёмся к объектам!

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

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

Объекты. Создание и сохранение объектов классов. Оператор 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; inew 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[i] = new CLine(i*2, i*1.5, i+2.2, i-1); > // использование массива, вычисление суммарной длины всех отрезков double sumLength = 0; for (int i=0; i"Sum color: #008000;">// Sum = 45.45345204172149 > >

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

  • Применение классов в программах на Java. Определение класса и объекта класса. Примеры
  • Область действия объектов (scope). Удаление объектов. Преимущества использования подхода «уборки мусора» (garbage collection) для объектов

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *