Инициализация переменных в методах класса. Инициализация полей (членов данных) класса. Способы инициализации членов данных класса

Инициализация переменных в методах класса. Инициализация полей (членов данных) класса. Способы инициализации членов данных класса

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


Содержание



1. Понятие инициализации переменных в методах в Java

Инициализация переменной означает явное (или неявное) установление некоторого значения переменной.

В языке программирования Java переменные, объявленные в методе, обязательно должны быть инициализированы перед их использованием.

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

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

static void SomeMethod()
{
    int t;
    int x;

    x = 6;
    x = x + t + 2; // здесь ошибка: переменная t не инициализирована
}

В этом случае выдается сообщение об ошибке:

The local variable t may not have been initialized

Чтобы исправить ситуацию, нужно переменной t присвоить какое-то значение перед ее использованием.

2. Какие существуют способы инициализации членов данных класса?

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

  • инициализация по умолчанию (неявная инициализация);
  • явная инициализация начальными значениями (константными значениями);
  • явная инициализация методами класса;
  • инициализация с помощью конструкторов классов.

3. Инициализация полей данных класса. Что такое инициализация полей данных класса по умолчанию?

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

То есть, если есть класс в котором объявлены внутренние переменные (поля класса)

class SomeClass
{
    int d;
    double x;

    // ...
}

то эти переменные (d, x) будут инициализированы значением по умолчанию. В вышеприведенном коде переменным по умолчанию будут присвоены следующие значения

d = 0.0
x = 0

Не имеет значения, какой идентификатор доступа используется для переменной (private, protected, public) в классе.

 

4. Какие значения по умолчанию присваиваются полям класса для разных типов?

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

int      => 0
boolean  => false
double   => 0.0
float    => 0.0
char     => ' ' - нуль-символ
long     => 0
byte     => 0

Символьной переменной типа char присваивается нуль-символ, который отображается в виде символа «пробел».

5. Каким значением инициализируется переменная-ссылка на объект класса?

Если в классе объявляется переменная-ссылка на объект некоторого класса, то по умолчанию, значение этой ссылки равно null.

Нижеследующий фрагмент кода демонстрирует это.

// некоторый класс
public class InnerClass
{
    // ...
}

// класс, в котором объявлен объект класса InnerClass
public class MyClass
{
    // ...

    public static InnerClass obj; // obj = null; - по умолчанию

    // ...
}

В вышеприведенном примере переменная obj есть ссылкой (reference) на класс InnerClass. Другими словами obj это объект класса InnerClass. Поскольку, память для obj еще не выделена, то по умолчанию значение obj = null.

6. Явная инициализация. Каким образом осуществляется явная инициализация членов данных класса начальными значениями?

Явная инициализация означает установление начального (нужного) значения переменной при ее объявлении в классе.

Например. В классе MyClass реализована инициализация начальными значениями переменных разных типов.

public class CTrain01
{
    // явная инициализация начальных значений переменных
    int d = 25; // явная инициализация переменной d типа int значением 25
    float y = 3.885f;
    public double x = -129.48;
    boolean b = true;
    char c = 'Z';
    long l = 0xF3309FA;

    // ...
}

В языках C/C++ такой способ инициализации не допускается.

7. Каким образом осуществляется явная инициализация членов данных класса, которые есть переменными-ссылками на класс

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

class InnerClass
{
    // ...
}

class MyClass
{
    // ...

    // явная инициализация переменной obj в классе MyClass
    InnerClass obj = new InnerClass();

    // ...
}

В классе MyClass переменная-ссылка obj перед ее использованием обязательно должна быть инициализирована оператором new. Если попробовать использовать неинициализированную переменную, которая есть ссылкой на класс, возникнет критическая ситуация (исключение).

8. Явная инициализация с помощью вызова методов. Каким образом инициализируется значение члена данных класса с помощью вызова метода?

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

Например. Пусть задан класс CRadius. В классе CRadius инициализируются члены данных len, area, volume с помощью вызова методов Length(), Area(), Volume(). Эти методы вычисляют соответственно длину окружности, площадь круга и объем шара радиуса r, который есть входным параметром методов.

public class CRadius
{
    // скрытые переменные
    private double Pi = 3.1415;
    private double radius=1;

    // общедоступные переменные
    public double len = Length(radius); // инициализация переменной len методом Length()
    public double area = Area(radius); // инициализация переменной area методом Area()
    public double volume = Volume(radius); // инициализация переменной volume методом Volume()

    // методы вычисления
    double Length(double r)     { return 2*Pi*r; }
    double Area(double r)   { return Pi*r*r; }
    double Volume(double r) { return 4.0/3.0*Pi*r*r*r; }

    public static void main(String[] args)
    {
        // демонстрация инициализации методами класса CRadius
        CRadius r1 = new CRadius(); // происходит явная инициализация членов данных объекта r1
        double l, a, v;

        l = r1.len; // l = 6.283;
        a = r1.area; // a = 3.1415
        v = r1.volume; // v = 4.1886666666
    }
}

9. Какой порядок инициализации при объявлении переменных? Какое значение имеет порядок инициализации при объявлении переменных? Примеры

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

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

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

// в классе демонстрируется правильный порядок инициализации
public class CInitOrderClass
{
    int t1 = 5;
    int t2 = SomeMethod(); // t2 = 100;
    int t3 = t2; // t3 = 100
    int t4 = t1 + t3; // t4 = 5 + 100 = 105
    int t5 = SomeMethod() + t4; // t5 = 205

    // метод, который используется при инициализации
    int SomeMethod()
    {
        return 100;
    }

    public static void main(String[] args)
    {
        // Демонстрация использования объекта класса CInitOrderClass
        CInitOrderClass obj = new CInitOrderClass();
        int d;

        d = obj.t1; // d = 5
        d = obj.t2; // d = 100
        d = obj.t3; // d = 100
        d = obj.t4; // d = 105
        d = obj.t5; // d = 205
    }
}

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

public class CInitOrderClass
{
    int t4 = t1 + t3; // t4 = ??? - здесь ошибка, переменные t1, t3 еще не объявлены
    int t1 = 5;
    int t2 = SomeMethod(); // t2 = 100;
    int t3 = t2; // t3 = 100
    int t5 = SomeMethod() + t4; // t5 = 205

    // ...
}

то возникнет ошибка компиляции

Cannot reference a field before it is defined

Это логично, поскольку просмотр объявлений переменных происходит сверху-вниз (от начала до конца). На момент объявления переменной t4, переменные t1 и t3, которые принимают участие в инициализации, еще не объявлены. Это есть причиной возникновения ошибки.

Это не касается метода класса SomeMethod(), который может использоваться при инициализации в любом месте класса.

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

Пусть дана реализация класса COrderInit, в котором инициализируются три переменные a, b, c с помощью метода InitMethod() и с помощью конструктора COrderInit().

// в классе демонстрируется порядок инициализации
public class COrderInit
{
    int a = InitMethod("a = "); // инициализация переменной a с помощью метода

    // инициализация переменных конструктором
    COrderInit()
    {
        a = b = c = 0;
        System.out.println("Constructor COrderInit().");
    }

    int c = InitMethod("c = "); //инициализация переменной c

    // метод, инициализирующий переменные
    int InitMethod(String s)
    {
        System.out.println(s + "InitMethod().");
        return 100;
    }

    int b = InitMethod("b = "); // инициализация переменной b

    public static void main(String[] args)
    {       
        COrderInit obj = new COrderInit();
    }
}

Как видно из вышеприведенного кода, класс содержит функцию main(), в которой создается объект класса COrderInit. Метод класса InitMethod() получает входным параметром строку s. Эта строка выводит строку инициализации с именем соответствующей переменной.

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

a = InitMethod().
c = InitMethod().
b = InitMethod().
Constructor COrderInit().

Результат показывает, что первой происходит инициализация переменных a, c, b. Порядок инициализации переменных определяется порядком их объявления в классе. После этого происходит вызов конструктора.

10. Каким образом осуществляется инициализация с помощью конструктора?

Инициализация членов данных класса с помощью конструктора более подробно описывается в теме:

11. Каким образом можно инициализировать члены данных класса с помощью секции инициализации { }? Пример

Члены данных класса можно инициализировать в одной секции, как показано в примере.

public class CDataInit
{
    int a, b, c, d;

    // инициализация с помощью секции инициализации { }
    {
        a = 1;
        b = 2;
        c = 3;
        d = 4;
    }

    public static void main(String[] args)
    {
        CDataInit obj = new CDataInit();
        int t;

        t = obj.a; // t = 1
        t = obj.b; // t = 2
        t = obj.c; // t = 3
        t = obj.d; // t = 4
    }
}

12. Что выполняется первым: секция инициализации или конструктор?

Первым выполняется секция инициализации а потом уже конструктор класса.


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