sonyps4.ru

Java почему конструктор заменяют методом. Конструкторы

Метод в Java - это комплекс выражений, совокупность которых позволяет выполнить определенную операцию. Так, например, при вызове метода System.out.println(), система выполняет ряд команд для выведения сообщения на консоль.

На данном этапе вы освоите технику создания собственных методов с либо без возвращаемых значений, вызова методов с указанием либо без указания параметров, и выделения методов при разработке программы.

Создание метода

Ниже рассмотрен пример, иллюстрирующий синтаксис метода, как в Java создать метод.

Синтаксис

public static int methodName(int a, int b) { // тело }
  • public static - модификатор;
  • int - возвращаемый тип;
  • methodName - имя метода;
  • a, b - формальные параметры;
  • int a, int b - перечень параметров.

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

Синтаксис

modifier returnType nameOfMethod (Parameter List) { // тело метода }

Приведенный выше синтаксис включает:

  • modifier – определяет тип доступа для метода и возможность его использования.
  • returnType – метод может возвратить значение.
  • nameOfMethod – указывает имя метода. Сигнатура метода включает имя метода и перечень параметров.
  • Parameter List – перечень параметров представлен типом, порядком и количеством параметров метода. Данная опция задается произвольно, в методе может присутствовать нулевой параметр.
  • method body – тело метода определяет метод работы с командами.

Пример

/* фрагмент кода возвращает минимальное между двумя числами */ public static int minFunction(int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; }

Вызов метода

Перед использованием метода его необходимо вызвать. Существует два способа для вызова метода в Java, т.е. метод производит возврат значения либо не производит (отсутствует возвращающее значение).

Алгоритм вызова метода достаточно прост. Когда программа производит в Java вызов метода, программное управление передается вызванному методу. Данный вызванный метод затем возвращает управление вызывающему клиенту в двух случаях, если:

  • выполняется оператор возврата;
  • достигнута закрывающая фигурная скобка окончания метода.

Метод возврата типа void производит вызов команды. Рассмотрим пример:

System.out.!");

Метод возврата значения может быть проиллюстрирован следующим примером:

Int result = sum(6, 9);

Пример ниже демонстрирует способ определения и вызова метода в Java.

Пример

public class ExampleMinNumber { public static void main(String args) { int a = 11; int b = 6; int c = minFunction(a, b); System.out.println("Минимальное значение = " + c); } /* Возвращает минимум из двух чисел */ public static int minFunction(int n1, int n2) { int min; if (n1 >

Минимальное значение = 6

Ключевое слово void

Ключевое слово void в Java позволяет нам создать методы, не производящие возврат значения. В примере, расположенном далее, нами был рассмотрен метод типа void – methodRankPoints. Методы типа void в Java не производят возврат каких-либо значений. Вызов метода типа void выполняется командой, т.е. methodRankPoints(255.7);. Это java-выражение, которое оканчивается точкой с запятой, как показано в примере ниже:

Пример

public class ExampleVoid { public static void main(String args) { methodRankPoints(255.7); } public static void methodRankPoints(double points) { if (points >= 202.5) { System.out.println("Ранг A1"); }else if (points >= 122.4) { System.out.println("Ранг A2"); }else { System.out.println("Ранг A3"); } } }

В итоге будет получен следующий результат:

Ранг A1

Передача параметров по значению в Java

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

В Java передача параметров по значению обозначает вызов метода с параметром. За счет этого производится передача значения аргумента параметру.

Пример

Следующая программа демонстрирует пример передачи параметра по значению. Значения аргументов остаются неизменными даже после вызова метода.

Public class swappingExample { public static void main(String args) { int a = 30; int b = 45; System.out.println("Перед тем как передать, значения аргументов a = " + a + " и b = " + b); // Вызов метода передачи swapFunction(a, b); System.out.println("\nСейчас, до и после передачи значения аргументов "); System.out.println("остались неизменными, a = " + a + " и b = " + b); } public static void swapFunction(int a, int b) { System.out.println("До замены: a = " + a + " b = " + b); // Передача параметров int c = a; a = b; b = c; System.out.println("После замены: a = " + a + " b = " + b); } }

Получим следующий результат:

Перед тем как передать, значения аргументов a = 30 и b = 45 До замены: a = 30 b = 45 После замены: a = 45 b = 30 Сейчас, до и после передачи значения аргументов остались неизменными, a = 30 и b = 45

Перегрузка методов

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

Рассмотрим пример, который был представлен выше при определении минимальных чисел целочисленного типа. Так допустим, мы хотим определить минимальное число двойного типа. В данном случае будет представлена концепция перегрузки для создания двух и более методов с одинаковым именем, но различными параметрами.

Рассмотренный пример поясняет вышесказанное.

Пример

public class ExampleOverloading { public static void main(String args) { int a = 7; int b = 3; double c = 5.1; double d = 7.2; int result1 = minFunction(a, b); // такая же функция с другими параметрами double result2 = minFunction(c, d); System.out.println("Минимальное значение = " + result1); System.out.println("Минимальное значение = " + result2); } // для integer public static int minFunction(int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; } // для double public static double minFunction(double n1, double n2) { double min; if (n1 > n2) min = n2; else min = n1; return min; } }

В итоге будет получен следующий результат:

Минимальное значение = 3 Минимальное значение = 5.1

Методы перегрузки делают программу читаемой. Таким образом, представлены два метода с одинаковым именем, но различными параметрами. В результате чего мы получили минимальные int число и число double типа.

Использование аргументов командной строки

В ходе работы программы вам может понадобиться произвести передачу определенной информации. Это может быть сделано в Java за счет передачи аргументов командной строки в main().

В Java аргумент командной строки представляет информацию, которая напрямую следует за именем программы в командной строке при ее выполнении. Получение доступа к аргументам командной строки в java-программе не представляет сложности. Они хранятся в виде строки в массиве строк, переданном в main().

Пример

Программа ниже отображает все вызванные аргументы командной строки.

Public class CommandLine { public static void main(String args) { for(int i = 0; i

Попробуйте выполнить данную программу, как показано далее:

$java CommandLine это командная строка 300 -200

В итоге будет получен следующий результат:

Args: это args: командная args: строка args: 300 args: -200

Конструктор в Java

В Java конструктор инициализирует объект при его создании. Его имя аналогично имени класса, а синтаксис сходен с синтаксисом метода. Однако, в отличие от последнего, в конструкторе отсутствует возвращаемое значение.

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

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

Пример

В примере ниже рассмотрено использование конструктора класса без параметров.

// Простой конструктор. class MyClass { int x; // Далее следует конструктор MyClass() { x = 10; } }

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

Public class ConsDemo { public static void main(String args) { MyClass t1 = new MyClass(); MyClass t2 = new MyClass(); System.out.println(t1.x + " " + t2.x); } }

Получим результат:

Параметризованный конструктор

Чаще всего вам может понадобиться конструктор, который принимает один и более параметров. Добавление параметров к конструктору аналогично их добавлению в метод, следует только внести их в круглые скобки после имени конструктора.

Пример

// Простой конструктор. class MyClass { int x; // Ниже конструктор MyClass(int i) { x = i; } }

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

Public class ConsDemo { public static void main(String args) { MyClass t1 = new MyClass(10); MyClass t2 = new MyClass(20); System.out.println(t1.x + " " + t2.x); } }

Получим следующий результат:

Ключевое слово this

Ключевое слово this - используется для ссылки на текущий класс с учетом метода или конструктора экземпляра. Используя this в Java, Вы можете ссылаться на экземпляры класса, такие как конструкторы, переменные и методы.

Примечание: ключевое слово this используется только в составе методов либо конструкторов экземпляра.

Как правило, ключевое слово this в Java используется для:

  • дифференцирования между переменными экземпляра и локальными переменными в случае, если у них одинаковые имена, в составе конструктора или метода.
class Student { int age; Student(int age) { this.age = age; } }
  • вызова конструктора одного типа (параметризованного конструктора либо конструктора по умолчанию) из другого в составе класса. Данный процесс также носит название явного вызова конструктора.
class Student { int age Student() { this(20); } Student(int age) { this.age = age; } }

Пример

Public class This_Example { // Инициализация переменной num int num = 11; This_Example() { System.out.println("Это пример программы с ключевым словом this"); } This_Example(int num) { // Вызов конструктора по умолчанию this(); // Присвоение локальной переменной num переменной экземпляра num this.num = num; } public void greet() { System.out.println("Привет! Добро пожаловать на ProgLang!"); } public void print() { // Локальная переменная num int num = 20; // Вызов метода класса greet this.greet(); // Вывод локальной переменной. System.out.println("Значение локальной переменной num: " + num); // Вывод переменной экземпляра. System.out.println("Значение переменной экземпляра num: " + this.num); } public static void main(String args) { // Инициализация класса This_Example obj1 = new This_Example(); // Вызов метода print obj1.print(); // Передача нового значения переменной num через параметризованный конструктор This_Example obj2 = new This_Example(30); // Вызов снова метода print obj2.print(); } }

В итоге будет получен следующий результат:

Это пример программы с ключевым словом this Привет! Добро пожаловать на ProgLang! Значение локальной переменной num: 22 Значение переменной экземпляра num: 11 Это пример программы с ключевым словом this Привет! Добро пожаловать на ProgLang! Значение локальной переменной num: 22 Значение переменной экземпляра num: 30

Аргументы переменной (var-args)

JDK 1.5 и выше позволяет передавать методу переменное количество аргументов одного типа. Параметр в методе объявляется следующим образом:

TypeName... parameterName

При объявлении метода Вы указываете тип, за которым следует многоточие (...). В методе может быть указан только один параметр переменной длины, и этот параметр должен быть последним параметром. Любые регулярные параметры должны предшествовать ему.

Пример

public class VarargsDemo { public static void main(String args) { // Вызов метода с переменной args printMax(27, 11, 11, 5, 77.1); printMax(new double{10, 11, 12, 77, 71}); } public static void printMax(double... numbers) { if (numbers.length == 0) { System.out.println("Ни один аргумент не передается"); return; } double result = numbers; for (int i = 1; i result) result = numbers[i]; System.out.println("Максимальное значение " + result); } }

В итоге будет получен следующий результат:

Максимальное значение 77.1 Максимальное значение 77.0

Метод finalize()

Метод finalize() - метод, который будет вызываться непосредственно перед окончательным уничтожением объекта сборщиком мусора. (финализатором). В Java finalize() может быть использован для обеспечения чистого завершения объекта.

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

Для добавления финализатора в класс, вам просто следует определить метод finalize() в Java. Среда выполнения Java производит вызов данного метода непосредственно перед обработкой объекта данного класса.

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

В общем виде метод finalize() выглядит следующим образом:

Protected void finalize() { // здесь финализация кода }

Здесь ключевое слово protected представляет спецификатор, предотвращающий доступ к finalize() посредством кода, определяемого вне его класса.

Это свидетельствует о том, что вы не можете знать как или даже когда будет производиться выполнение finalize(). К примеру, если ваша программа будет окончена до «сборки мусора», finalize() не будет выполняться.

What is Constructor in Java?

A constructor is a special method that is used to initialize a newly created object and is called just after the memory is allocated for the object. It can be used to initialize the objects to desired values or default values at the time of object creation. It is not mandatory for the coder to write a constructor for a class.

If no user-defined constructor is provided for a class, compiler initializes member variables to its default values.

  • numeric data types are set to 0
  • char data types are set to null character(‘\0’)
  • reference variables are set to null

In this tutorial, you will learn-

Rules for creating a Java Constructor

  1. It has the same name as the class
  2. It should not return a value not even void

Example 1 : Create your First Constructor Java

Step 1) Type following code in your editor.

Class Demo{ int value1; int value2; Demo(){ value1 = 10; value2 = 20; System.out.println("Inside Constructor"); } public void display(){ System.out.println("Value1 === "+value1); System.out.println("Value2 === "+value2); } public static void main(String args){ Demo d1 = new Demo(); d1.display(); } }

Step 2) Save , Run & Compile the code. Observe the output.

Inside Constructor Value1 === 10 Value2 === 20

Constructor Overloading

Constructor overloading is a technique in Java in which a class can have any number of constructors that differ in parameter list. The compiler differentiates these constructors by taking into account the number of parameters in the list and their type.

Examples of valid constructors for class Account are

Account(int a); Account (int a,int b); Account (String a,int b);

Example 2 : To understand Constructor Overloading

Step 1) Type the code in the editor.

Class Demo{ int value1; int value2; /*Demo(){ value1 = 10; value2 = 20; System.out.println("Inside 1st Constructor"); }*/ Demo(int a){ value1 = a; System.out.println("Inside 2nd Constructor"); } Demo(int a,int b){ value1 = a; value2 = b; System.out.println("Inside 3rd Constructor"); } public void display(){ System.out.println("Value1 === "+value1); System.out.println("Value2 === "+value2); } public static void main(String args){ Demo d1 = new Demo(); Demo d2 = new Demo(30); Demo d3 = new Demo(30,40); d1.display(); d2.display(); d3.display(); } }

Step 2) Save, Compile & Run the Code.

Step 3) Error = ?. Try and debug the error before proceeding to next step.

Step 4) Every class has a default Constructor. Default Constructor for class Demo is Demo() . In case you do not provide this constructor the compiler creates it for you and initializes the variables to default values. You may choose to override this default constructor and initialize variables to your desired values as shown in Example 1.

But if you specify a parametrized constructor like Demo(int a), and want to use the default constructor Demo(), it is mandatory for you to specify it.

In other words, in case your Constructor is overridden, and you want to use the default constructor, its need to be specified.

Step 5) Uncomment line # 4-8. Save, Compile & Run the code.

Constructor Chaining

Consider a scenario where a base class is extended by a child. Whenever an object of the child class is created, the constructor of the parent class is invoked first. This is called Constructor chaining.

Example 3: To understand constructor chaining

Step 1) Copy the following code into the editor.

Class Demo{ int value1; int value2; Demo(){ value1 = 1; value2 = 2; System.out.println("Inside 1st Parent Constructor"); } Demo(int a){ value1 = a; System.out.println("Inside 2nd Parent Constructor"); } public void display(){ System.out.println("Value1 === "+value1); System.out.println("Value2 === "+value2); } public static void main(String args){ DemoChild d1 = new DemoChild(); d1.display(); } } class DemoChild extends Demo{ int value3; int value4; DemoChild(){ //super(5); value3 = 3; value4 = 4; System.out.println("Inside the Constructor of Child"); } public void display(){ System.out.println("Value1 === "+value1); System.out.println("Value2 === "+value2); System.out.println("Value1 === "+value3); System.out.println("Value2 === "+value4); } }

Step 2) Run the Code. Owing to constructor chaining, when the object of child class DemoChild is created, constructor Demo() of the parent class is invoked first and later constructor DemoChild() of the child is created. Expected Output =

Inside 1st Parent Constructor Inside the Constructor of Child Value1 === 1 Value2 === 2 Value1 === 3 Value2 === 4

Step 3) You may observe the constructor of the parent class Demo is overridden. What if you want to call the overridden constructor Demo(int a) instead of the default constructor Demo() when your child object is created?

In such cases, you can use the keyword "super" to call overridden constructors of the parent class.

Syntax:-

Super(); --or-- super(parameter list);

Example: If your constructor is like Demo(String Name,int a) you will specify super("Java",5) If used, the keyword super needs to be the first line of code in the constructor of the child class.

Step 4) Uncomment Line # 26 and run the code. Observe the Output.

Inside 2nd Parent Constructor Inside the Constructor of Child Value1 === 5 Value2 === 0 Value1 === 3 Value2 === 4

Для достижения целей, выходящих за рамки потребностей простой инициализации, в составе класса предусмотрены специальные члены – конструкторы (constructors). Конструктор – это блок выражений, которые используются для инициализации созданного объекта. Инициализация выполняется до того момента, когда оператор new вернет в вызывающий блок ссылку на объект. Конструкторы обладают тем же именем, что и класс, в составе которого они объявляются. Подобно обычным методам класса, конструкторы способны принимать любое (в том числе и нулевое) число аргументов, но в отличие от методов не могут возвращать значения какого бы то ни было типа. При создании объекта класса, содержащего конструктор, который объявлен с параметрами, оператор new сопровождается наименованием класса и списком соответствующих аргументов, заключенным в круглые скобки. Конструкторы вызываются после присваивания полям вновь созданного объекта значений по умолчанию и выполнения явных инструкций инициализации полей.

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

public long idNUm;

public String name = "<Без имени>";

public Body orbits = null;

private static long nextID = 0;

idNUm = nextID++;

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

Конструктор класса Body объявлен без параметров. Его назначение довольно важно – он обеспечивает уникальность значения поля idNum вновь создаваемого объекта класса. В исходном варианте класса небольшая ошибка программиста-пользователя, связанная, например, с неаккуратно выполненной операцией присваивания значения полю idNum либо с отсутствием инструкций приращения содержимого поля nextID, могла бы привести к тому, что несколько объектов Body получили бы один и тот же порядковый номер. Подобный результат явно Ошибочен, поскольку нарушает ту часть контракта класса, которая гласит:

"Значения idNum различных объектов класса должны быть уникальными".

Передав ответственность за выбор верных значений idNum самому классу, мы раз и навсегда избавимся от подобных ошибок. Теперь конструктор класса Body – это единственный субъект, который изменяет содержимое поля nextID и нуждается в доступе к нему. Поэтому мы можем и должны обозначить переменную nextID модификатором private, чтобы предотвратить возможность обращения к ней за пределами класса. Сделав это, мы исключим один из потенциальных источников ошибок, грозящих будущим пользователям нашего класса.

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

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

Body sun = new Body(); // idNUm = 0

sun. name = "Солнце";

Body earth = new Body(); // idNum = 1

earth.name = "земля";

earth.orbits = sun;

В Процессе создания объекта с помощью оператора new конструктор класса Body Вызывается после присваивания полям name и огbits предусмотренных нами Выражений инициализации.

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

Body(String bodyName, Body orbitsAround) {

name = bodyName; orbits = orbitsAround;

Как нетрудно заметить, один конструктор класса обращается к другому посредством выражения this – первой исполняемой инструкции в теле конструктора-инициатора. Подобное предложение называют явным вызовом конструктора. Если конструктор, к которому вы намереваетесь обратиться явно, предполагает задание аргументов, при вызове они должны быть переданы. Какой из конструкторов будет вызван – это обусловливается количеством аргументов и набором их типов. В данном случае выражение this означает вызов конструктора без параметров, позволяющего установить значение idNum объекта и увеличить текущее содержимое статического поля nextID на единицу. Обращение к this дает возможность избежать повторения кода инициализации idNum и изменения nextID. Теперь код, предусматривающий создание объектов, становится существенно более простым:

Body sun = new Bоdу("солнце", null);

Body earth = new Воdу("земля", sun);

Версия конструктора, вызываемого в процессе выполнения оператора new, определяется структурой списка передаваемых аргументов.

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

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

Body(String bodyName) {

this (bodyName, null);

Здесь вновь используется прием явного вызова конструктора.

Нередки ситуации, когда в контракте класса содержится требование о том, чтобы код, ответственный за создание объектов этого класса, предоставлял конструкторам класса дополнительную информацию. Например, вы как автор класса Body можете оговорить такое условие: "Все объекты класса Body должны обладать именем". Чтобы гарантировать его выполнение, вы вправе включить в список параметров каждого из конструкторов класса параметр имени – теперь вам не придется заботиться об инициализации поля name.

Ниже перечислено несколько причин, обусловливающих применение специализированных конструкторов.

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

· При использовании дополнительных конструкторов задача определения начальных свойств объектов упрощается (наглядный пример – конструктор класса Body с двумя параметрами).

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

· Если конструктор не помечен признаком publiс, круг субъектов, которые могут им воспользоваться для создания экземпляров класса, ограничивается. Вы вправе, например, запретить программистам, использующим пакет, создавать объекты класса, предусмотрев для всех конструкторов класса признак доступа на уровне пакета.

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

будет помечен как publiс.

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

Body(Body other) {

idNum = other.idNum;

name = other.name;

orbits = other.orbits;

Подход к решению задачи копирования объектов, связанный с применением специальных конструкторов, в классах стандартных пакетов Java широкого распространения не нашел, поскольку для достижения подобной цели более предпочтительным считается использование метода Сlone (обратитесь к разделу 3.9 на странице 111). Впрочем, простой конструктор копии предусмотрен, например, в составе класса String, а в классах коллекций (они рассматриваются в главе 16)

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

В тексте конструкторов допускается упоминание объявляемых исключений.

Предложение throws помещается после списка параметров непосредственно Перед открывающей фигурной скобкой, которая отмечает начало тела конструктора. Если в объявлении конструктора присутствует предложение throws, любой метод, который косвенным образом обращается к конструктору при выполнении оператора new, обязан либо обеспечить "отлов" исключений упомянутых типов с помощью соответствующих предложений catch, либо перечислить эти типы в разделе throws собственного объявления.

Дело в том, что:

1. Если Вы создаете класс и в нем определяете конструктор с аргументами (класс AClass, у которого только один конструктор, который принимает int i), то компилятор уже не создаст конструктор по умолчанию. Потому что это нарушило бы контракт класса AClass, который не может быть инициализирован без аргументов. Если Вы хотите еще иметь и конструктор по умолчанию, задавайте теперь его явно.

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

2. При создании конструкторов класса BClass, который наследуется от другого класса, компилятор требует, чтобы первой строкой конструктора был вызов другого конструктора (унаследованного или в этом классе).

Почему? Потому что раз Вы наследуетесь от какого-то класса, Вы хотите повторно использовать его логику. Конструктор приводит экземпляр класса в какое-то начальное целостное состояние. В Вашем случае для инициализации AClass требует аргумент, без которого JVM не знает, как инициализировать экземпляр класса.

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

Public class AClass1 { }

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

Это эквивалентно такому определению:

Public class AClass1 { public AClass1() { } }

Теперь посмотрим на BClass1:

Public class BClass1 extends AClass1 { }

Здесь тоже явно конструкторы не определены, и компилятор пытается создать конструктор по умолчанию. Поскольку в классе AClass1 есть конструктор по умолчанию, он создаст конструктор по умолчанию, который будет вызывать конструктор AClass1. Этот код эквивалентен такому:

Public class BClass1 extends AClass1 { public BClass1() { super(); } }

В Вашем случае создается класс БЕЗ конструктора по умолчанию:

Public AClass { public AClass(int i) { } }

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

AClass a = new AClass(); // не работает

нужно что-то вроде

AClass a = new AClass(1);

Соответственно, любой конструктор BClass будет требовать вызова какого-либо конструктора AClass или BClass. При таком описании компилятор будет ругаться:

Public BClass extends AClass { }

Потому что будет попытка вызова конструкора по умолчанию класса AClass, который не определен:

Public BClass extends AClass { public BClass() { super(); // ошибка; в классе AClass нет такого конструктора } }

Тем не менее, можно создать класс BClass с конструктором по умолчанию, задав какое-то значение для конструктора AClass:

Public class BClass extends AClass { public BClass() { super(1); } }

Это будет компилироваться.

1. Понятие конструктора по умолчанию

Конструктор по умолчанию (default constructor) – это конструктор, который не имеет параметров. Конструктор по умолчанию может объявляться в классе явным образом или генерироваться автоматически.

В наиболее общем случае, для класса ClassName , конструктор по умолчанию имеет следующий вид:

class ClassName { ... // объявление конструктора ClassName() { // тело конструктора // ... } ... }
2. В каких случаях конструктор по умолчанию генерируется в классе автоматически а в каких нет? Пример

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

Например. В следующем объявлении класса конструктор по умолчанию генерируется автоматически

class CMyClass { int d ; int GetD() { return d ; } void SetD(int nd) { d = nd; } }

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

// работает, так как в классе больше не реализовано ни одного конструктора CMyClass mc = new CMyClass();

Если в тело класса CMyClass добавить хотя бы один другой конструктор (например, конструктор с одним параметром), то конструктор по умолчанию автоматически генерироваться не будет

class CMyClass { int d ; // конструктор по умолчанию уже не генерируется автоматически CMyClass(int nd) { d = nd; } int GetD() { return d ; } void Set(int nd) { d = nd; } }

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

// ошибка компиляции, так как в классе уже объявлен другой конструктор // CMyClass mc = new CMyClass(); CMyClass mc2 = new CMyClass(7); // а этот код работает

В результате выполнения вышеприведенной строки будет выдана ошибка компиляции:

The constructor CMyClass() is undefined

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

class CMyClass { int d ; // явное объявление конструктора по умолчанию CMyClass() { d = 0; } // объявление конструктора с 1 параметром, CMyClass(int nd) { d = nd; } int GetD() { return d ; } void Set(int nd) { d = nd; } }

После такой реализации можно создавать экземпляр класса с использованием двух конструкторов, например

CMyClass mc = new CMyClass(); // вызывается конструктор по умолчанию mc.d = 25; CMyClass mc2 = new CMyClass(5); // вызывается конструктор с 1 параметром

3. Вызов конструкторов из других конструкторов. Пример

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

Пример. В примере демонстрируется использование класса CPixel , который реализует пиксел на экране монитора.

// Класс, который реализует пиксел на экране монитора public class CPixel { // внутренние переменные класса private int x , y ; // координаты пиксела private int color ; // цвет пиксела // конструктор без параметров (конструктор по умолчанию) CPixel() { x = y = color = 0; } // конструктор с 2 параметрами, которые инициализируют только координаты CPixel(int _x, int _y) { x = _x; y = _y; color = 0; } // конструктор с 1 параметром, который инициализирует только цвет CPixel(int _color) { color = _color; x = y = 0; } // конструктор с 3 параметрами, который вызывает конструктор с 2 параметрами CPixel (int _x, int _y, int _color) { // вызов конструктора с 2 параметрами: обязательно первая операция и только один раз this (_x, _y); //this(_color); // повторный вызов конструктора запрещен this .color = _color; // так можно } // методы доступа int GetX() { return x ; } int GetY() { return y ; } int GetColor() { return color ; } }

Использование класса CPixel в другом программном коде (методе)

CPixel cp1 = new CPixel(2,8); // вызов конструктора с 2 параметрами CPixel cp2 = new CPixel(3,5,8); // вызов конструктора, который вызовет другой конструктор int d; d = cp1.GetX(); // d = 2 d = cp2.GetColor(); // d = 8 d = cp2.GetY(); // d = 5 ...

4. Какие ограничения (требования) накладываются на вызов других конструкторов из конструктора класса?

Чтобы корректно вызвать другие конструкторы из конструктора класса, нужно придерживаться следующих требований (ограничений):

  • вызвать можно только один другой конструктор класса. Вызвать два и больше других конструктора этого класса запрещено. Это вытекает из логики, что конструктор класса предназначен для создания объекта класса только один раз (а не два и больше раза);
  • вызов другого конструктора должен быть первой операцией в вызывающем конструкторе. Если в вызывающем конструкторе вызов другого конструктора реализовать второй (третьей и т.д.) операцией, то компилятор выдаст ошибку.


Загрузка...