Требуется ли вызывать конструктор для инициализации переменных значениями по умолчанию? - PullRequest
0 голосов
/ 02 ноября 2018

Я пытался пройти почти каждую статью здесь об инициализации переменных, но я все еще не понимаю кое-что об этом. Мне не ясно, если мы должны вызывать конструктор для инициализации переменных экземпляра значениями по умолчанию, или это может произойти без вызова конструктора? Например, соглашение заключается в том, что каждый класс, написанный нами на Java, вызывает конструктор суперкласса в своем конструкторе для «инициализации переменных» суперкласса. Что это значит? Нужно ли вызывать конструктор суперкласса для инициализации переменных экземпляра суперкласса значениями по умолчанию? Или даже без invokin переменные экземпляра конструктора суперкласса имеют значения по умолчанию, и мы делаем это, чтобы передать им значения, описанные в конструкторе или заданные во время объявления? Во-вторых, мы можем инициализировать переменные двумя способами, не давая им значений (они будут установлены в значения по умолчанию), давая значения в объявлении, например:

private int number = 10;

или указание значений в конструкторе. Для меня очевидно, что мы должны вызывать конструктор для инициализации переменных значениями, указанными в конструкторе, но как насчет других 2 примеров? Нужно ли также вызывать конструктор для инициализации переменной экземпляра этими значениями? Может ли кто-нибудь также дать мне заказ на создание этого простыми словами? Я знаю, что здесь много статей о порядке создания и инициализации объектов, и я прочитал их все, но я до сих пор не понимаю многих вещей там. И скажите мне, если я ошибаюсь, но то, что я понял, ответ на вопрос, что мы должны вызвать конструктор суперкласса для инициализации полей суперкласса их значениями по умолчанию, потому что в противном случае не будет никакого смысла делать вызов Конструкторы суперкласса необходимы, если переменные экземпляра суперкласса уже были бы инициализированы со значениями по умолчанию без вызова конструктора - потому что нам не нужно беспокоиться о том, что наши переменные неинициализированы, если они есть - со значениями по умолчанию.

@ РЕДАКТИРОВАТЬ: Чтобы было ясно, мой главный вопрос был: Когда переменные экземпляра получают значение по умолчанию? В конструкторе или перед конструктором? Должен ли конструктор вызываться для инициализации переменных экземпляра, или значения по умолчанию назначаются еще до вызова конструктора?

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Согласно JLS 4.12.5 :

Каждая переменная в программе должна иметь значение, прежде чем ее значение используется:

Каждая переменная класса, переменная экземпляра или компонент массива инициализируется значением по умолчанию при его создании (§15.9, §15.10.2):

Для байта типа значением по умолчанию является ноль, то есть значение (Байт) 0. * +1010 *

Для типа short значение по умолчанию равно нулю, то есть значение (Короткий) 0.

Для типа int значение по умолчанию равно нулю, то есть 0.

Для типа long значение по умолчанию равно нулю, то есть 0L.

Для типа float значением по умолчанию является положительный ноль, то есть 0,0f.

Для типа double значением по умолчанию является положительный ноль, то есть 0,0d.

Для типа char значением по умолчанию является нулевой символ, то есть '\ U0000'.

Для типа boolean значением по умолчанию является false.

Для всех ссылочных типов (§4.3) значение по умолчанию равно нулю.

Каждый параметр метода (§8.4.1) инициализируется соответствующим значение аргумента, предоставленное инициатором метода (§15.12).

Каждый параметр конструктора (§8.8.1) инициализируется соответствующее значение аргумента, предоставленное созданием экземпляра класса выражение (§15.9) или явный вызов конструктора (§8.8.7).

Параметр исключения (§14.20) инициализируется для брошенного объекта представляющих исключение (§11.3, §14.18).

Локальной переменной (§14.4, §14.14) должно быть явно задано значение перед его использованием, либо инициализацией (§14.4), либо присвоением (§15.26), таким образом, который может быть проверен с использованием правил для определенных назначение (§16 (Определенное назначение)).

Таким образом, если ваше поле нигде не инициализируется перед его использованием, начальное (или значение по умолчанию) будет null для объектных / ссылочных типов, false для примитивного boolean типа или 0 для любых других типов примитивов (0 для char - это null символ).

Если поле инициализировано, то нам нужно посмотреть на порядок.

private class A {
    protected int a = 2;

    public A() {
        System.out.println("Printing from constructor of A");
        printValues();
        System.out.println();
    }

    public void printValues() {
        System.out.println("a = " + a);
    }
}

private class B extends A {
    private int b = 3;
    private int c = initC();

    public B() {
        super();

        System.out.println("Printing from constructor of B");
        printValues();
        System.out.println();
    }

    @Override
    public void printValues() {
        super.printValues(); // Call parent implementation

        System.out.println("b = " + b);
        System.out.println("c = " + c);
    }

    private int initC() {
        System.out.println("Printing from initC()");
        printValues();
        System.out.println();

        return 4;
    }

    public static void main(String[] args) {
        new B();
    }
}

Создает:

Printing from constructor of A
a = 2
b = 0
c = 0

Printing from initC()
a = 2
b = 3
c = 0

Printing from constructor of B
a = 2
b = 3
c = 4

В конструкторе A (который является родительским классом), a (который принадлежит A) уже инициализирован с 2. Другие 2 поля остаются не инициализированными, возвращая значения, указанные в JLS 4.12.5.

Затем конструктор A завершает работу и возвращается обратно в конструктор B (дочерний класс). Вы могли бы ожидать, что он перейдет к части конструктора B, но перед этим произошло нечто другое - вызывается initC(). В этот момент мы видим, что b также был инициализирован, но c не был инициализирован, поскольку initC() должен возвращать значение для инициализации c.

Наконец, мы видим, как инициализируются все 3 поля.

Так что это порядок:

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

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

0 голосов
/ 02 ноября 2018

Когда переменные экземпляра получают значение по умолчанию? В конструкторе или перед конструктором?

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

Должен ли конструктор вызываться для инициализации переменных экземпляра, или значения по умолчанию назначаются еще до вызова конструктора?

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

Например, это:

class B extends A {
     public B() {}
}

эквивалентно этому:

class B extends A {
     public B() {
         super();
     }
}

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

Конструктор всегда вызывается.

0 голосов
/ 02 ноября 2018

На объектно-ориентированных языках программирования «Объект» играет ключевую роль. Итак, инициация объекта обязательна. Я не мог точно понять, что вы спрашиваете .. Я говорю по моим сведениям.

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

Class_Name object = new Class_Name();

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

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

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

Вы можете изменить значение создаваемой переменной, передав параметр в конструкторе.

Если вы не указали значения для ваших переменных. Компилятор установит для этого значение по умолчанию. Посмотрите на эту статью https://www.javaworld.com/article/2076614/core-java/object-initialization-in-java.html

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