Перейти к основному содержимому

Тип возврата конструктора в Java

· 3 мин. чтения

1. Обзор

В этом кратком руководстве мы сосредоточимся на типе возвращаемого значения для конструктора в Java.

Во-первых, мы познакомимся с тем, как работает инициализация объектов в Java и JVM. Затем мы копнем глубже, чтобы увидеть, как инициализация и присваивание объектов работают «под капотом».

2. Инициализация экземпляра

Начнем с пустого класса:

public class Color {}

Здесь мы собираемся создать экземпляр из этого класса и присвоить его некоторой переменной:

Color color = new Color();

После компиляции этого простого Java-фрагмента давайте взглянем на его байт-код с помощью команды javap -c :

0: new           #7                  // class Color
3: dup
4: invokespecial #9 // Method Color."<init>":()V
7: astore_1

Когда мы создаем экземпляр объекта в Java, JVM выполняет следующие операции:

  1. Во- первых, он находит место в пространстве своего процесса для нового объекта.
  2. Затем JVM выполняет процесс инициализации системы. На этом этапе он создает объект в состоянии по умолчанию. Новый код операции в байт-коде фактически отвечает за этот шаг.
  3. Наконец, он инициализирует объект с помощью конструктора и других блоков инициализатора. В этом случае код операции invokespecial вызывает конструктор.

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

Method Color."<init>":()V

<init> — это имя методов инициализации экземпляра в JVM . В данном случае <init> — это функция, которая:

  • ничего не принимает на вход (пустые скобки после имени метода)
  • ничего не возвращает (V означает void )

Следовательно, возвращаемый тип конструктора в Java и JVM — void.

Еще раз взглянем на наше простое задание:

Color color = new Color();

Теперь, когда мы знаем, что конструктор возвращает void , давайте посмотрим, как работает присваивание.

3. Как работает назначение

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

./8fa8270b598f53310cdca86ee4cca5e6.svg

Каждый кадр стека использует массив для хранения локальных переменных и стек операндов для хранения частичных результатов . Учитывая это, давайте еще раз посмотрим на байт-код:

0: new           #7                // class Color
3: dup
4: invokespecial #9 // Method Color."<init>":()V
7: astore_1

Вот как работает задание:

  • Новая инструкция создает экземпляр Color и помещает его ссылку в стек операндов. ``
  • Код операции dup дублирует последний элемент в стеке операндов.
  • Invokespecial берет дубликат ссылки и использует ее для инициализации. После этого в стеке операндов остается только исходная ссылка.
  • astore_1 хранит исходную ссылку на индекс 1 массива локальных переменных. Префикс «а» означает, что сохраняемый элемент является ссылкой на объект, а «1» — это индекс массива.

Отныне второй элемент (индекс 1) в массиве локальных переменных является ссылкой на только что созданный объект . Поэтому мы не теряем ссылку, и присваивание действительно работает — даже когда конструктор ничего не возвращает!

4. Вывод

В этом кратком руководстве мы узнали, как JVM создает и инициализирует экземпляры нашего класса. Более того, мы увидели, как инициализация экземпляра работает «под капотом».

Для еще более подробного понимания JVM всегда полезно ознакомиться с ее спецификацией .