JavaRush /Java Blog /Random EN /Class constructors. Java JDK 1.5
articles
Level 15

Class constructors. Java JDK 1.5

Published in the Random EN group
Class constructors.  Java JDK 1.5 - 1

General information about constructors

Конструкторis a structure similar to a method, the purpose of which is to create an instance of a class. Characteristics of the designer:
  • The name of the constructor must match the name of the class (by convention, the first letter is capitalized, usually a noun);
  • There is a constructor in any class. Even if you don't write one, the Java compiler will create a default constructor, which will be empty and do nothing other than call the superclass constructor.
  • A constructor is similar to a method, but it is not a method, it is not even considered a member of the class. Therefore, it cannot be inherited or overridden in a subclass;
  • Constructors are not inherited;
  • There can be several constructors in a class. In this case, the constructors are said to be overloaded;
  • If a class does not define a constructor, the compiler automatically adds a parameterless constructor to the code;
  • A constructor does not have a return type; it cannot even be a type void; if a type is returned void, then it is no longer a constructor but a method, despite the coincidence with the class name.
  • The operator is allowed in the constructor return, but only empty, without any return value;
  • The constructor allows the use of access modifiers; you can set one of the modifiers: public, protected, privateor without a modifier.
  • A constructor cannot have the modifiers abstract, final, native, staticor synchronized;
  • The keyword thisrefers to another constructor in the same class. If used, the call to it must be the first line of the constructor;
  • The keyword supercalls the constructor of the parent class. If used, the reference to it must be the first line of the constructor;
  • If the constructor does not make a call to the superancestor class's constructor (with or without arguments), the compiler automatically adds code to call the ancestor class's constructor without arguments;

Default constructor

There is a constructor in any class. Even if you don't write one, the Java compiler will create a default constructor. This constructor is empty and does nothing other than call the superclass constructor. Those. if you write:
public class Example {}
then this is equivalent to writing:
public class Example
{
     Example()
     {
          super;
     }
}
In this case, the ancestor class is not explicitly specified, and by default, all Java classes inherit the class, Objectso the class constructor is called Object. If a class defines a parameterized constructor, but there is no overloaded parameterless constructor, then calling the parameterless constructor is an error. However, in Java since version 1.5, it is possible to use constructors with variable length arguments. And if there is a constructor that has a variable length argument, then calling the default constructor will not be an error. It won't because the variable length argument can be empty. For example, the following example will not compile, but if you uncomment the constructor with a variable length argument, it will compile and run successfully and result in a line of code running DefaultDemo dd = new DefaultDemo(); the constructor will be called DefaultDemo(int ... v). Naturally, in this case it is necessary to use JSDK 1.5. FileDefaultDemo.java
class DefaultDemo
{
 DefaultDemo(String s)
 {
  System.out.print("DefaultDemo(String)");
 }
 /*
 DefaultDemo(int ... v)
 {
  System.out.println("DefaultDemo(int ...)");
 }
 */

 public static void main(String args[])
 {
  DefaultDemo dd = new DefaultDemo();
 }
}
The result of the program output with the constructor uncommented:
DefaultDemo(int ...)
However, in the common case where the class does not define any constructor at all, calling the default constructor (without parameters) will be necessary, since default constructor substitution occurs automatically.

Object creation and constructors

When creating an object, the following actions are performed sequentially:
  • The object class is searched among the classes already used in the program. If it is not there, then it is searched in all catalogs and libraries available to the program. Once a class is discovered in a directory or library, the class's static fields are created and initialized. Those. For each class, static fields are initialized only once.
  • Memory is allocated for the object.
  • The class fields are being initialized.
  • The class constructor executes.
  • A link to the created and initialized object is formed. This reference is the value of the expression that creates the object. An object can also be created by calling a newInstance()class method java.lang.Class. In this case, a constructor without a parameter list is used.

Overloading constructors

Constructors of the same class can have the same name and different signature. This property is called combination or overloading. If a class has multiple constructors, then constructor overloading is present.

Parameterized Constructors

The signature of a constructor is the number and types of parameters, as well as the sequence of their types in the list of constructor parameters. The return type is not taken into account. The constructor does not return any parameters. This statement explains, in a sense, how Java distinguishes between overloaded constructors or methods. Java distinguishes overloaded methods not by their return type, but by the number, types, and sequence of types of input parameters. A constructor cannot even return a type void, otherwise it will turn into a regular method, even though it is similar to the class name. The following example demonstrates this. FileVoidDemo.java
class VoidDemo
{
 /**
  * Это конструктор
  */
 VoidDemo()
 {
  System.out.println("Constructor");
 }

 /**
  * А это уже обычный метод, даже не смотря на сходство с
  * именем класса, поскольку имеется возвращаемый тип void
  */
 void VoidDemo()
 {
  System.out.println("Method");
 }

 public static void main(String s[])
 {
  VoidDemo m = new VoidDemo();
 }
}
As a result, the program will output:
Constructor
This once again proves that a constructor is a method without return parameters. However, the constructor can be given one of three modifiers public, , privateor protected. And the example will now look like this: FileVoidDemo2.java
class VoidDemo2
{
 /**
  * Это конструктор
  */
 public VoidDemo2()
 {
  System.out.println("Constructor");
 }

 /**
  * А это уже обычный метод, даже не смотря на сходство с
  * именем класса, поскольку имеется возвращаемый тип void
  */
 private void VoidDemo2()
 {
  System.out.println("Method");
 }

 public static void main(String s[])
 {
  VoidDemo2 m = new VoidDemo2();
 }
}
It is allowed to write an operator in a constructor return, but only an empty one, without any return value. FileReturnDemo.java
class ReturnDemo
{
 /**
  * В конструкторе допускается использование оператора
  * return без параметров.
  */
 public ReturnDemo()
 {
  System.out.println("Constructor");
  return;
 }

 public static void main(String s[])
 {
  ReturnDemo r = new ReturnDemo();
 }
}

Constructors parameterized with variable-length arguments

Java SDK 1.5 introduced a long-awaited tool - variable-length arguments for constructors and methods. Previously, a variable number of documents were processed in two inconvenient ways. The first of them was designed to ensure that the maximum number of arguments is limited to a small number and is known in advance. In this case, it was possible to create overloaded versions of the method, one for each version of the list of arguments passed to the method. The second method is designed for something unknown in advance and a large number of arguments. In this case, the arguments were placed in an array, and this array was passed to the method. Variable length arguments are most often involved in subsequent manipulations with variable initializations. It is convenient to replace the absence of some of the expected constructor or method arguments with default values. The variable length argument is an array, and is treated as an array. For example, the constructor for a class Checkingwith a variable number of arguments would look like this:
class Checking
{
 public Checking(int ... n)
 {
 }
}
The character combination ... tells the compiler that a variable number of arguments will be used, and that these arguments will be stored in an array whose reference value is contained in the variable n. The constructor can be called with a different number of arguments, including no arguments at all. The arguments are automatically placed in an array and passed through n. If there are no arguments, the length of the array is 0. The list of parameters, along with variable length arguments, can also include mandatory parameters. In this case, a parameter containing a variable number of arguments must necessarily be the last in the list of parameters. For example:
class Checking
{
 public Checking(String s, int ... n)
 {
 }
}
A very obvious limitation concerns the number of variable length parameters. There must be only one variable-length parameter in the parameter list. Given two variable-length parameters, it is impossible for the compiler to determine where one parameter ends and the other begins. For example:
class Checking
{
 public Checking(String s, int ... n, double ... d) //ОШИБКА!
 {
 }
}
File Checking.java For example, there is equipment capable of recognizing car license plates and remembering the numbers of the squares of the area where each of the cars visited during the day. It is necessary to select from the total mass of recorded cars those that during the day visited two given squares, say 22 and 15, according to the area map. It is quite natural that a car can visit many squares during the day, or maybe only one. Obviously, the number of squares visited is limited by the physical speed of the car. Let's create a small program where the class constructor will take as arguments the car number as a mandatory parameter and the numbers of visited squares of the area, the number of which can be variable. The constructor will check whether a car has appeared in two squares; if it has, then display its number on the screen.

Passing parameters to the constructor

There are mainly two types of parameters in programming languages:
  • basic types (primitives);
  • references to objects.
The term call by value means that the constructor receives the value passed to it by the calling module. In contrast, call by reference means that the constructor receives the address of the variable from the caller. Java uses call by value only. By parameter value and by parameter link value. Java does not use call by reference for objects (although many programmers and the authors of some books claim this). When passing objects to Java, parameters are passed not by reference , but by the value of the object reference ! In either case, the constructor receives copies of the values ​​of all parameters. The constructor cannot do with its input parameters:
  • the constructor cannot change the values ​​of the input parameters of the main (primitive) types;
  • the constructor cannot change input parameter references;
  • the constructor cannot reassign input parameter references to new objects.
The constructor can do with its input parameters:
  • change the state of the object passed as an input parameter.
The following example proves that in Java, input parameters to a constructor are passed by object reference value. This example also reflects that the constructor cannot change the references of the input parameters, but actually changes the references of copies of the input parameters. FileEmpoyee.java
class Employee
{
 Employee(String x, String y)
 {
  String temp = x;
  x = y;
  y = temp;
 }
 public static void main(String args[])
 {
  String name1 = new String("Alice");
  String name2 = new String("Mary");
  Employee a = new Employee(name1, name2);
  System.out.println("name1="+name1);
  System.out.println("name2="+name2);
 }
}
The output of the program is:
name1=Alice
name2=Mary
If Java used call by reference to pass objects as parameters, the constructor would swap name1and in this example name2. The constructor will not actually swap the object references stored in the name1and variables name2. This suggests that the constructor parameters are initialized with copies of these references. Then the constructor swaps the copies. When the constructor completes its work, the x and y variables are destroyed, and the original variables name1continue name2to refer to the previous objects.

Changing the parameters passed to the constructor.

The constructor cannot modify the passed parameters of basic types. However, the constructor can modify the state of the object passed as a parameter. For example, consider the following program: FileSalary1.java
class Salary1
{
 Salary1(int x)
 {
  x = x * 3;
  System.out.println("x="+x);
 }
 public static void main(String args[])
 {
  int value = 1000;
  Salary1 s1 = new Salary1(value);
  System.out.println("value="+value);
 }
}
The output of the program is:
x=3000
value=1000
Obviously, this method will not change the main type parameter. Therefore, after calling the constructor, the value of the variable valueremains equal to 1000. Essentially three things happen:
  1. The variable xis initialized with a copy of the parameter value value(i.e., a number 1000).
  2. The value of the variable xis tripled - it is now equal to 3000. However, the value of the variable valueremains equal to 1000.
  3. The constructor terminates and the variable xis no longer used.
In the following example, the employee's salary is successfully tripled because the value of an object reference is passed as a parameter to the method. FileSalary2.java
class Salary2
{
 int value = 1000;
 Salary2()
 {
 }
 Salary2(Salary2 x)
 {
  x.value = x.value * 3;
 }
 public static void main(String args[])
 {
  Salary2 s1 = new Salary2();
  Salary2 s2 = new Salary2(s1);
  System.out.println("s1.value=" +s1.value);
  System.out.println("s2.value="+s2.value);
 }
}
The output of the program is:
s1.value=3000
s2.value=1000
The value of the object reference is used as a parameter. When executing the line Salary2 s2 = new Salary2(s1); the constructor Salary2(Salary x)will be passed the value of a reference to the variable object s1, and the constructor will effectively triple the salary for s1.value, since even the copy (Salary x)created inside the constructor points to the variable object s1.

Constructors parameterized by primitives.

If the parameters of an overloaded constructor use a primitive that can be narrowed (for example int <- double), then calling a method with a narrowed value is possible, despite the fact that there is no method overloaded with such a parameter. For example: FilePrimitive.java
class Primitive
{
 Primitive(double d)
 {
  d = d + 10;
  System.out.println("d="+d);
 }
 public static void main(String args[])
 {
  int i = 20;
  Primitive s1 = new Primitive(i);
 }
}
The output of the program is:
d=30.0
Despite the fact that the class Primitivedoes not have a constructor that has a type parameter int, a constructor with an input parameter will work double. Before calling the constructor, the variable iwill be expanded from type intto type double. The opposite option, when the variable iwould be of type double, and the constructor would only have a parameter int, in this situation would lead to a compilation error.

Constructor call and operatornew

The constructor is always called by the operator new. When a constructor is called with the operator new, the constructor always generates a reference to a new object. It is impossible to force the constructor to form a reference to an already existing object instead of a reference to a new object, except by substituting the object being deserialized. And with the new operator, instead of a reference to a new object, it is impossible to form a reference to an already existing object. For example: FileSalary3.java
class Salary3
{
 int value = 1000;
 Salary3()
 {
 }
 Salary3(Salary3 x)
 {
  x.value = x.value * 3;
 }
 public static void main(String args[])
 {
  Salary3 s1 = new Salary3();
  System.out.println("First object creation: "+s1.value);

  Salary3 s2 = new Salary3(s1);
  System.out.println("Second object creation: "+s2.value);
  System.out.println("What's happend with first object?:"+s1.value);

  Salary3 s3 = new Salary3(s1);
  System.out.println("Third object creation: "+s3.value);
  System.out.println("What's happend with first object?:"+s1.value);
 }
}
The output of the program is:
First object creation: 1000
Second object creation: 1000
What's happend with first object?: 3000
Third object creation: 1000
What's happend with first object?: 9000
First, using the line Salary3 s1 = new Salary3(); a new object is created. Next, if using the line Salary3 s2 = new Salary3(s1); or strings Salary3 s3 = new Salary3(s1); it would be possible to create a link to an already existing object, then s1.value s2.valuethey s3.valuewould store the same value 1000. Actually in the line Salary3 s2 = new Salary3(s1); a new object for the variable will be created s2and the state of the object for the variable will change s1by passing its reference value to the object in the constructor parameter. This can be verified by the output results. And when executing the line Salary3 s3 = new Salary3(s1); a NEW object for the variable will be created s3and the state of the object for the variable will change again s1.

Constructors and initialization blocks, sequence of actions when calling a constructor

The section Creating an Object and Constructors lists the general actions that are performed when creating an object. Among them are the processes of initializing class fields and working out the class constructor, which in turn also have an internal order:
  1. All data fields are initialized to their default values ​​(0, false, or null).
  2. All field initializers and initialization blocks are executed in the order they are listed in the class declaration.
  3. If another constructor is called on the first line of a constructor, then the called constructor is executed.
  4. The body of the constructor is executed.
The constructor is related to initialization because in Java there are three ways to initialize a field in a class:
  • assign a value in the declaration;
  • assign values ​​in the initialization block;
  • set its value in the constructor.
Naturally, you need to organize the initialization code so that it is easy to understand. The following class is given as an example:
class Initialization
{
 int i;
 short z = 10;
 static int x;
 static float y;
 static
 {
  x = 2000;
  y = 3.141;
 }
 Initialization()
 {
  System.out.println("i="+i);
  System.out.println("z="+z);
  z = 20;
  System.out.println("z="+z);
 }
}
In the example above, the variables are initialized in the following order: static variables are initialized first xwith ydefault values. Next, the static initialization block is executed. Then the variable is initialized ito the default value and the variable is initialized z. Next, the designer gets to work. Calling class constructors should not depend on the order in which fields are declared. This may lead to errors.

Constructors and inheritance

Constructors are not inherited. For example:
public class Example
{
 Example()
 {
 }
 public void sayHi()
 {
  system.out.println("Hi");
 }
}

public class SubClass extends Example
{
}
The class SubClassautomatically inherits the method sayHi()defined in the parent class. At the same time, the constructor Example()of the parent class is not inherited by its descendant SubClass.

Keyword thisin constructors

Constructors are used thisto refer to another constructor in the same class, but with a different list of parameters. If the constructor uses the keyword this, then it must be on the first line; ignoring this rule will result in a compiler error. For example: FileThisDemo.java
public class ThisDemo
{
 String name;
 ThisDemo(String s)
 {
  name = s;
     System.out.println(name);
 }
 ThisDemo()
 {
  this("John");
 }
 public static void main(String args[])
 {
  ThisDemo td1 = new ThisDemo("Mary");
  ThisDemo td2 = new ThisDemo();
 }
}
The output of the program is:
Mary
John
In this example there are two constructors. The first one receives a string argument. The second one does not receive any arguments, it simply calls the first constructor using the default name "John". Thus, you can use constructors to initialize field values ​​explicitly and by default, which is often necessary in programs.

Keyword superin constructors

Constructors are used superto call a superclass constructor. If the constructor uses super, then this call must be on the first line, otherwise the compiler will throw an error. Below is an example: FileSuperClassDemo.java
public class SuperClassDemo
{
 SuperClassDemo()
 {
 }
}

class Child extends SuperClassDemo
{
 Child()
 {
  super();
 }
}
In this simple example, the constructor Child()contains a call super()that creates an instance of the class SuperClassDemo, in addition to the class Child. Because superit must be the first statement executed in a subclass constructor, this order is always the same and does not depend on whether super(). If it is not used, then the default (no parameters) constructor of each superclass, starting with the base class, will be executed first. The following program demonstrates when constructors are executed. FileCall.java
//Создать суперкласс A
class A
{
 A()
 {
  System.out.println("Inside A constructor.");
 }
}

//Создать подкласс B, расширяющий класс A
class B extends A
{
 B()
 {
  System.out.println("Inside B constructor.");
 }
}

//Создать класс (C), расширяющий класс В
class C extends B
{
 C()
 {
  System.out.println("Inside C constructor.");
 }
}

class Call
{
 public static void main(String args[])
 {
  C c = new C();
 }
}
Output from this program:
Inside A constructor.
Inside B constructor.
Inside C constructor.
Constructors are called in order of class subordination. This makes some sense. Since the superclass has no knowledge of any subclass, any initialization it needs to perform is separate. If possible, it should precede any initialization performed by the subclass. That's why it should be done first.

Customizable constructors

The run-time type identification mechanism is one of the powerful core principles of the Java language that implements polymorphism. However, such a mechanism does not protect the developer from incompatible type casting in some cases. The most common case is the manipulation of a group of objects, the various types of which are unknown in advance and are determined at run time. Since errors associated with type incompatibility can only appear at the runtime stage, this makes them difficult to find and eliminate. The introduction of custom types in Java 2 5.0 moves some of these errors from runtime to compile time and provides some of the missing type safety. There is no need for explicit type casting when moving from a type Objectto a concrete type. It should be kept in mind that type customization tools work only with objects and do not apply to primitive data types that lie outside the class inheritance tree. With custom types, all casts are performed automatically and behind the scenes. This allows you to protect against type mismatches and reuse code much more often. Custom types can be used in constructors. Constructors can be custom even if their class is not a custom type. For example:
class GenConstructor
{
 private double val;
 <T extends Number> GenConstructor(T arg)
 {
   val = arg.doubleValue();
 }

 void printValue()
 {
  System.out.println("val: "+val);
 }
}

class GenConstructorDemo
{
 public static void main(String args[])
 {
  GenConstructor gc1 = new GenConstructor(100);
  GenConstructor gc2 = new GenConstructor(123.5F);

  gc1.printValue();
  gc2.printValue();
 }
}
Because the constructor GenConstructorspecifies a custom type parameter that must be a derived class from class Number, it can be called from any
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION