Вот мой код:
class A {
static A obj = new A();
static int num1;
static int num2=0;
private A() {
num1++;
num2++;
}
public static A getInstance() {
return obj;
}
}
public class Main{
public static void main(String[] arg) {
A obj = A.getInstance();
System.out.println(obj.num1);
System.out.println(obj.num2);
}
}
Вывод есть 1 0
, но я не могу понять.
Может кто-нибудь мне это объяснить?
Ответы:
В Java проходят две фазы: 1. Идентификация, 2. Выполнение.
На этапе идентификации все статические переменные обнаруживаются и инициализируются значениями по умолчанию.
Итак, теперь значения:
A obj=null
num1=0
num2=0
Второй этап, выполнение , начинается сверху вниз. В Java выполнение начинается с первых статических членов.
Здесь ваша первая статическая переменная
static A obj = new A();
, поэтому сначала она создаст объект этой переменной и вызовет конструктор, поэтому значениеnum1
иnum2
станет1
.А потом снова
static int num2=0;
будет казнен, что делаетnum2 = 0;
.Теперь предположим, что ваш конструктор выглядит так:
Это вызовет ошибку,
NullPointerException
посколькуobj
еще нет ссылкиclass A
.источник
static A obj = new A();
ниже,static int num2=0;
и вы должны получить 1 и 1.A obj = new A(); int num1; int num2 = 0;
Преобразуемый это:A obj; int num1; int num2; obj = new A(); num2 = 0;
. Java делает это, поэтомуnum1, num2
они определяются к моменту достиженияnew A()
конструктора.Что
static
означает модификатор , когда применяется к декларации переменной является то , что переменная является переменной класса , а не переменная экземпляра. Другими словами ... есть только однаnum1
переменная и только однаnum2
переменная.(Кроме того: статическая переменная похожа на глобальную переменную в некоторых других языках, за исключением того, что ее имя не отображается везде. Даже если оно объявлено как a
public static
, неполное имя отображается только в том случае, если оно объявлено в текущем классе или суперклассе. , или если он импортируется с использованием статического импорта. В этом различие. Настоящий глобальный вид нигде виден без уточнения.)Поэтому , когда вы смотрите
obj.num1
иobj.num2
вы на самом деле имея в виду на статические переменные, вещественные обозначенияA.num1
иA.num2
. И аналогично, когда конструктор увеличиваетnum1
иnum2
, он увеличивает те же переменные (соответственно).Непонятная морщина в вашем примере заключается в инициализации класса. Класс инициализируется, сначала инициализируя по умолчанию все статические переменные, а затем выполняя объявленные статические инициализаторы (и блоки статического инициализатора) в том порядке, в котором они появляются в классе. В этом случае у вас есть это:
Бывает так:
Статика начинается с начальных значений по умолчанию;
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
... и это то, что показывают ваши операторы печати.Это сбивающее с толку поведение на самом деле связано с тем, что вы создаете экземпляр до завершения статической инициализации и что используемый вами конструктор зависит от статического объекта, который еще не инициализирован, и изменяет его. Этого вам следует избегать в реальном коде.
источник
1,0 правильно.
Когда класс загружается, все статические данные инициализируются или объявляются. По умолчанию int равно 0.
static int num1;
ничего не делаетstatic int num2=0;
это записывает 0 в num2источник
Это связано с порядком статических инициализаторов. Статические выражения в классах оцениваются в порядке сверху вниз.
Первым вызывается конструктор
A
, который устанавливаетnum1
иnum2
оба значения в 1:static A obj = new A();
Затем,
вызывается и снова устанавливает num2 = 0.
Вот почему
num1
1 иnum2
0.В качестве примечания, конструктор не должен изменять статические переменные, это очень плохой дизайн. Вместо этого попробуйте другой подход к реализации синглтона в Java .
источник
Раздел в JLS можно найти: §12.4.2 .
Таким образом, три статические переменные будут инициализированы одна за другой в текстовом порядке.
Так
Если я изменю порядок на:
Результат будет
1,1
.Обратите внимание, что
static int num1;
это не инициализатор переменной, потому что ( §8.3.2 ):И эта переменная класса инициализируется при создании класса. Это происходит первым ( §4.12.5 ).
источник
Может быть, стоит подумать об этом таким образом.
Классы - это чертежи объектов.
Объекты могут иметь переменные при их создании.
Классы также могут иметь переменные. Они объявлены как статические. Таким образом, они устанавливаются для класса, а не для экземпляров объекта.
Вы можете иметь только один из любого класса в приложении, так что это своего рода глобальное хранилище специально для этого класса. Разумеется, к этим статическим переменным можно получить доступ и изменить их из любого места в вашем приложении (при условии, что они общедоступны).
Вот и пример класса «Dog», который использует статическую переменную для отслеживания количества созданных экземпляров.
Класс «Dog» - это облако, а оранжевые прямоугольники - это экземпляры «Dog».
читать далее
Надеюсь это поможет!
Если вам хочется мелочей, эту идею впервые предложил Платон.
источник
Ключевое слово static используется в java в основном для управления памятью. Мы можем применять ключевое слово static с переменными, методами, блоками и вложенным классом. Ключевое слово static принадлежит классу, а не экземпляру класса. Краткое объяснение ключевого слова static:
http://www.javatpoint.com/static-keyword-in-java
источник
Многие из приведенных выше ответов верны. Но на самом деле, чтобы проиллюстрировать, что происходит, я сделал несколько небольших изменений ниже.
Как уже неоднократно упоминалось выше, происходит то, что экземпляр класса A создается до полной загрузки класса A. Так что то, что считается нормальным «поведением», не наблюдается. Это не слишком отличается от вызова методов из конструктора, который можно переопределить. В этом случае переменные экземпляра могут не находиться в интуитивно понятном состоянии. В этом примере переменные класса не находятся в интуитивно понятном состоянии.
Выход
источник
java не инициализирует значение какого-либо статического или нестатического элемента данных, пока он не будет вызван, но создает его.
так что здесь, когда num1 и num2 будут вызываться в основном, он будет инициализирован значениями
число1 = 0 + 1; и
num2 = 0;
источник