Що staticмодифікатор означає при застосуванні до оголошення змінної, це те, що змінна є змінною класу, а не змінною екземпляра. Іншими словами ... існує лише одна num1змінна і лише одна num2змінна.
(Убік: статична змінна схожа на глобальну змінну в деяких інших мовах, за винятком того, що її ім’я не видно скрізь. Навіть якщо вона оголошена як public static, некваліфіковане ім’я видно лише в тому випадку, якщо вона оголошена в поточному класі або надкласовій або якщо він імпортований за допомогою статичного імпорту. Це відмінність. Справжній глобальний світ видно без будь-якої кваліфікації.)
Тому , коли ви дивитеся obj.num1і obj.num2ви насправді маючи на увазі на статичні змінні, речові позначення A.num1і A.num2. І також, коли конструктор збільшується num1і num2, він збільшує ті самі змінні (відповідно).
Заплутана зморшка у вашому прикладі полягає в ініціалізації класу. Клас ініціалізується спочатку за замовчуванням ініціалізацією всіх статичних змінних, а потім виконанням оголошених статичних ініціалізаторів (та статичних блоків ініціалізаторів) у тому порядку, як вони відображаються в класі. У цьому випадку у вас є таке:
static A obj = new A();
static int num1;
static int num2=0;
Буває так:
Статика починається зі своїх стандартних початкових значень; A.objє nullі A.num1/ A.num2є нулем.
Перше оголошення ( A.obj) створює екземпляр A()і конструктор для Aзбільшення A.num1та A.num2. Коли декларація завершується A.num1і A.num2є обома 1, і A.objпосилається на щойно побудований Aекземпляр.
У другій декларації ( A.num1) немає ініціалізатора, тому A.num1не змінюється.
Третя заява ( A.num2) має ініціалізатор, який присвоює нуль A.num2.
Таким чином, наприкінці класу ініціалізація A.num1є 1і A.num2є 0... і ось що показують ваші друковані заяви.
Ця заплутана поведінка насправді зводиться до того, що ви створюєте екземпляр до завершення статичної ініціалізації, і що конструктор, який ви використовуєте, залежить від та змінює статику, яку ще слід ініціалізувати. Це те, чого вам слід уникати робити в реальному коді.