Значення за замовчуванням та ініціалізація в Java


77

Виходячи з мого посилання , примітивні типи мають значення за замовчуванням, а об’єкти - нульові. Я протестував шматок коду.

public class Main {
    public static void main(String[] args) {
        int a;
        System.out.println(a);
    }
}

Рядок System.out.println(a);буде помилкою, яка вказує на змінну, aяка говорить, variable a might not have been initializedтоді як у даному посиланні integerбуде мати 0значення за замовчуванням. Однак із наведеним нижче кодом він справді надрукується 0.

public class Main {
    static int a;
    public static void main(String[] args) {
        System.out.println(a);
    }
}

Що може піти не так з першим кодом? Чи мають клас екземпляр змінні поводяться відрізняються від локальних змінних?


А що друкується у другому? 0?
porfiriopartida

@porfiriopartida Так, на другому коді надруковано 0.
Michael 'Maik' Ardan

static context - це init, коли програма запускається, вона запускає значення за замовчуванням. 0 для int, порожній рядок для String, я вважаю, що це неправда для логічних типів тощо. Але для локальних цілей або для примірників ви можете ними керувати; Ви не можете гарантувати, коли або хто збирається отримати доступ до статичного атрибута.
porfiriopartida

Відповіді:


78

У першому зразку коду aє mainлокальна змінна методу. Локальні змінні методу потрібно ініціалізувати перед їх використанням.

У другому зразку коду aє змінною члена класу, отже, вона буде ініціалізована до значення за замовчуванням.


Я помічаю, що локальні змінні масиву методу не дають "змінної, можливо, не ініціалізованою" при використанні. Чи оголошені змінні методу як масиви ініціалізовані за замовчуванням, тоді як самостійні змінні - ні?
Androidcoder

Яке значення за замовчуванням у цьому випадку? Нуль якийсь?
Пітер Мортенсен

Примітиви @PeterMortensen не використовують значення null як значення за замовчуванням. Вони використовують допустиме значення для примітиву за замовчуванням, наприклад 0 для int. Повну інформацію можна знайти тут: docs.oracle.com/javase/tutorial/java/nutsandbolts/…
Джунід Ахсан

68

Прочитайте уважніше ваші посилання :

Значення за замовчуванням

Не завжди потрібно призначати значення при оголошенні поля . Поля , які оголошені, але не ініціалізовані, будуть встановлені розумним за замовчуванням компілятором. Взагалі кажучи, це значення за замовчуванням буде нульовим або нульовим, залежно від типу даних. Однак покладання на такі значення за замовчуванням, як правило, вважається поганим стилем програмування.

Наступна діаграма узагальнює значення за замовчуванням для вищезазначених типів даних.

. . .

Місцеві змінні дещо відрізняються; компілятор ніколи не призначає значення за замовчуванням неініціалізованій локальній змінній. Якщо вам не вдається ініціалізувати локальну змінну там, де вона оголошена, обов’язково призначте їй значення перед спробою використовувати її. Доступ до неініціалізованої локальної змінної призведе до помилки під час компіляції.


3
Я теж це читав, але як щодо масивів. масиви, що використовуються в локальному контексті, отримують значення за замовчуванням, але про це немає жодної згадки в документах.
Yahya Uddin

1
Там гарне пояснення масивів в місцевому контексті , як загальноприйнятому відповідь тут: stackoverflow.com/questions/13511702/int-array-initialization
gcbound

19

Це основні фактори, що беруть участь:

  1. змінна члена (за замовчуванням OK)
  2. статична змінна (за замовчуванням OK)
  3. кінцева змінна члена (не ініціалізована, повинна бути встановлена ​​на конструкторі)
  4. кінцева статична змінна (не ініціалізована, має бути встановлена ​​на статичному блоці {})
  5. локальна змінна (не ініціалізована)

Примітка 1. Ви повинні ініціалізувати змінні остаточного члена на кожному реалізованому конструкторі!

Примітка 2. Ви повинні ініціалізувати змінні остаточного члена всередині блоку самого конструктора, не викликаючи іншого методу, який їх ініціалізує. Наприклад, це НЕ діє:

private final int memberVar;

public Foo() {
    // Invalid initialization of a final member
    init();
}

private void init() {
    memberVar = 10;
}

Примітка 3: масиви є об’єктами в Java, навіть якщо вони зберігають примітиви.

Примітка 4: при ініціалізації масиву всі його елементи встановлюються за замовчуванням, незалежно від того, є членом або локальним масивом.

Я додаю приклад коду, представляючи вищезазначені випадки:

public class Foo {
    // Static and member variables are initialized to default values

    // Primitives
    private int a; // Default 0
    private static int b; // Default 0

    // Objects
    private Object c; // Default NULL
    private static Object d; // Default NULL

    // Arrays (note: they are objects too, even if they store primitives)
    private int[] e; // Default NULL
    private static int[] f; // Default NULL

    // What if declared as final?

    // Primitives
    private final int g; // Not initialized. MUST set in the constructor
    private final static int h; // Not initialized. MUST set in a static {}

    // Objects
    private final Object i; // Not initialized. MUST set in constructor
    private final static Object j; // Not initialized. MUST set in a static {}

    // Arrays
    private final int[] k; // Not initialized. MUST set in constructor
    private final static int[] l; // Not initialized. MUST set in a static {}

    // Initialize final statics
    static {
        h = 5;
        j = new Object();
        l = new int[5]; // Elements of l are initialized to 0
    }

    // Initialize final member variables
    public Foo() {
        g = 10;
        i = new Object();
        k = new int[10]; // Elements of k are initialized to 0
    }

    // A second example constructor
    // You have to initialize final member variables to every constructor!
    public Foo(boolean aBoolean) {
        g = 15;
        i = new Object();
        k = new int[15]; // Elements of k are initialized to 0
    }

    public static void main(String[] args) {
        // Local variables are not initialized
        int m; // Not initialized
        Object n; // Not initialized
        int[] o; // Not initialized

        // We must initialize them before use
        m = 20;
        n = new Object();
        o = new int[20]; // Elements of o are initialized to 0
    }
}

9

Є кілька речей, про які слід пам’ятати, оголошуючи примітивні значення типу.

Вони є:

  1. Значення, оголошені всередині методу, не отримуватимуть значення за замовчуванням.
  2. Значення, оголошені як змінні екземпляра або статичні змінні, матимуть значення за замовчуванням, яке дорівнює 0.

Отже, у вашому коді:

public class Main {
    int instanceVariable;
    static int staticVariable;
    public static void main(String[] args) {
        Main mainInstance = new Main()
        int localVariable;
        int localVariableTwo = 2;
        System.out.println(mainInstance.instanceVariable);
        System.out.println(staticVariable);
       // System.out.println(localVariable); // Will throw a compilation error
        System.out.println(localVariableTwo);
    }
}

3

Так, змінна екземпляра буде ініціалізована до значення за замовчуванням. Для локальної змінної вам потрібно ініціалізувати перед використанням:

public class Main {

    int instaceVariable; // An instance variable will be initialized to the default value

    public static void main(String[] args) {
        int localVariable = 0; // A local variable needs to be initialized before use
    }
}

2

Локальні змінні не отримують значень за замовчуванням. Їх початкові значення невизначені без присвоєння значень якимось чином. Перш ніж використовувати локальні змінні, їх слід ініціалізувати.

Існує велика різниця, коли ви оголошуєте змінну на рівні класу (як член, тобто як поле) та на рівні методу.

Якщо ви оголосите поле на рівні класу, вони отримують значення за замовчуванням відповідно до свого типу. Якщо ви оголошуєте змінну на рівні методу або як блок (означає будь-який код всередині {}), не отримують жодних значень і залишаються невизначеними, доки якимось чином вони не отримають якісь початкові значення, тобто деякі значення, призначені їм.


1

Усі змінні-члени повинні завантажуватися в купу, тому їх слід ініціалізувати значеннями за замовчуванням, коли створюється екземпляр класу.

У випадку локальних змінних вони не завантажуються в купу. Вони зберігаються в стосі, поки не будуть використані. Це перед Java 7, тому нам потрібно явно їх ініціалізувати.


1

У Java ініціалізація за замовчуванням застосовується лише до змінної екземпляра члена класу.

Це не застосовується для локальних змінних.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.