>  기사  >  Java  >  Java의 정적 변수 초기화에 대한 완전한 분석

Java의 정적 변수 초기화에 대한 완전한 분석

高洛峰
高洛峰원래의
2017-01-24 17:03:202305검색

정적 변수 초기화 순서
1. 간단한 규칙

가장 일반적인 JAVA 코드를 먼저 살펴보세요:

public class Test
{
 public static Test1 t = new Test1();
 public static int a = 0;
 public static int b;
 
 public static void main(String[] arg)
 {
  System.out.println(Test.a);
  System.out.println(Test.b);
 }
}
 
class Test1
{
 public Test1()
 {
  Test.a++;
  Test.b++;
 }
}

콘솔 출력이 무엇인지 맞춰보세요.

좋아요 , 아마도 아래 결과를 짐작하셨을 것입니다. 그러면 여전히 Java에 익숙하실 것입니다.

0 1

위 결과가 왜 출력되는지 이해가 안 되신다면 알려드리겠습니다.


Java 정적 변수 초기화는 다음 규칙을 따릅니다.

정적 변수는 선언 순서대로 선언되며 해당 유형의 기본값으로 설정됩니다. 그러나 초기화된 값을 할당하지는 않습니다.

선언이 완료된 후 초기화된 값을 선언한 순서대로 설정합니다. 초기화된 값이 없으면 건너뛰세요.

이 글을 읽고 나면 Test.a의 값이 세 번이나 변경되었음을 이해하게 될 것입니다.

선언 시 0으로 설정>>Test1::Test1에서 1로 설정>>Test.a는 0으로 초기화됩니다

복잡한 규칙

이해합니다. , 아래 코드를 다시 살펴보시기 바랍니다.

public class A
{
 public static int b = B.a;
 public static A plus =new A("A");
 public static final int finalInt = (int)(Math.random()*100);
 public static B p = new B("A");
 
 public static final String finalStr = "finalStr";
 public static final Integer finalInteger = new Integer(10);
 public static int a = 1;
 public static B c = null;
 
 public A(String from)
 {
  System.out.println("----------- begin A::A ----------------");
  System.out.println("A::A, from="+from);
  System.out.println("A::A, A.b="+A.b);
  System.out.println("A::A, A.finalInt="+A.finalInt);
  System.out.println("A::A, B.a="+B.a);
  System.out.println("A::A, B.plus="+B.plus);
  System.out.println("----------- end A::A ----------------");
 }
 
 public static void main(String[] arg)
 {
  System.out.println("main, A.b="+A.b);
  System.out.println("main, B.t="+B.t);
  System.out.println("main, C.a="+C.a);
 }
}
 
class B
{
 public static int t = A.a;
 public static A plus = new A("B");
 public static int a = 1;
 
 public B(String from)
 {
  System.out.println("----------- begin B::B ----------------");
  System.out.println("B::B, from="+from);
  System.out.println("B::B, B.a="+B.a);
  System.out.println("B::B, A.a="+A.a);
  System.out.println("B::B, A.p="+A.p);
  System.out.println("B::B, A.plus="+A.plus);
  System.out.println("B::B, A.finalInt="+A.finalInt);
  System.out.println("B::B, A.finalInteger="+A.finalInteger);
  System.out.println("B::B, A.finalStr="+A.finalStr);
  System.out.println("----------- end B::B ----------------");
 }
}
 
class C
{
 public static final A a = new A("C");
}

아직도 출력 결과를 추측할 수 있나요? 테스트하면서 작성 중이라 추측하지 못했습니다. ㅎㅎ

콘솔 출력 결과는

----------- begin A::A ----------------
A::A, from=B
A::A, A.b=0
A::A, A.finalInt=0
A::A, B.a=0
A::A, B.plus=null
----------- end A::A ----------------
----------- begin A::A ----------------
A::A, from=A
A::A, A.b=1
A::A, A.finalInt=0
A::A, B.a=1
A::A, B.plus=A@a90653
----------- end A::A ----------------
----------- begin B::B ----------------
B::B, from=A
B::B, B.a=1
B::B, A.a=0
B::B, A.p=null
B::B, A.plus=A@1fb8ee3
B::B, A.finalInt=61
B::B, A.finalInteger=null
B::B, A.finalStr=finalStr
----------- end B::B ----------------
main, A.b=1
main, B.t=0
----------- begin A::A ----------------
A::A, from=C
A::A, A.b=1
A::A, A.finalInt=61
A::A, B.a=1
A::A, B.plus=A@a90653
----------- end A::A ----------------
main, C.a=A@61de33

입니다. 이 결과는 짐작도 못하셨네요 ㅎㅎ

프로그램 실행 결과를 문장별로 설명하려면 아직 지면이 많이 필요합니다. 여기서는 Java 정적 변수 초기화에 따른 규칙을 직접 적어보겠습니다.

첫 번째 단락의 규칙은 여전히 ​​유효하지만 건전하지 않습니다.

클래스가 적극적으로 요청되는 경우에만 이 클래스가 초기화되며 정적 변수, 함수 및 기타 정적 항목만 포함됩니다.

상속 관계에서는 상위 클래스가 먼저 초기화됩니다.

정적 변수는 선언 순서대로 선언되어 해당 유형의 기본값으로 설정되지만 초기화된 값은 할당되지 않습니다.

이후 선언이 완료되면 초기화된 값으로 설정됩니다. 초기화된 값이 없으면 건너뛰세요.

A.b = B.a 초기화 시 A.b 초기화를 일시 중지하세요. 현재 클래스를 B로 변경하고 3단계로 점프하여 실행합니다.

B.plus = new A 초기화 시 B.plus 초기화를 일시 중지하고 A를 인스턴스화하여 B.plus에 할당합니다.

A의 생성자에서 B.a의 값을 구해야 할 때 B.a도 초기화되고, 일시정지된 초기화 상태에서 B.a가 초기화될 때까지 기다리지 않고 바로 B.a의 현재 값을 가져옵니다.

final. , 정적 상수는 실제로 일반 정적 변수의 초기화를 따르지만, 컴파일러는 사용된 위치에서 상수 값을 대체합니다.

정적 데이터 초기화
플러스 정적 한정 필드는 소위 클래스 필드입니다. 이는 이 필드의 소유권이 개체가 아니라 클래스임을 의미합니다. 얼마나 많은 객체가 생성되더라도 정적 데이터의 복사본은 하나만 있습니다.

클래스에서는 항상 정적 필드가 먼저 초기화되고 일반 필드가 초기화됩니다. 그런 다음 생성자를 초기화합니다. 하지만 이 클래스의 객체가 생성되지 않으면 객체는 초기화되지 않고 한 번만 실행됩니다.

다음 코드와 같이 StaticInitialization 클래스에서는 먼저 static Table table = new Table();을 초기화한 후 Table 객체를 초기화합니다. 그렇지 않으면 초기화되지 않습니다.

class Bowl {
 Bowl(int marker) {
 print("Bowl(" + marker + ")");
 }
 void f1(int marker) {
 print("f1(" + marker + ")");
 }
}
 
class Table {
 static Bowl bowl1 = new Bowl(1);
 Table() {
 print("Table()");
 bowl2.f1(1);
 }
 void f2(int marker) {
 print("f2(" + marker + ")");
 }
 static Bowl bowl2 = new Bowl(2);
}
 
class Cupboard {
 Bowl bowl3 = new Bowl(3);
 static Bowl bowl4 = new Bowl(4);
 Cupboard() {
 print("Cupboard()");
 bowl4.f1(2);
 }
 void f3(int marker) {
 print("f3(" + marker + ")");
 }
 static Bowl bowl5 = new Bowl(5);
}
 
public class StaticInitialization {
 public static void main(String[] args) {
 print("Creating new Cupboard() in main");
 new Cupboard();
 print("Creating new Cupboard() in main");
 new Cupboard();
 table.f2(1);
 cupboard.f3(1);
 }
 static Table table = new Table();
 static Cupboard cupboard = new Cupboard();
}

출력:

Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)

표시된 정적 초기화(즉, 정적 블록)
여러 초기화 문을 정적 블록이라고 하는 정적 중괄호로 래핑합니다. 이는 실제로 다중을 의미합니다. 정역학은 같이 쓴 것이고 본질은 같다. 객체가 처음 생성되거나 클래스의 필드에 처음으로 액세스할 때 한 번만 실행됩니다.

class Cup {
 Cup(int marker) {
 print("Cup(" + marker + ")");
 }
 void f(int marker) {
 print("f(" + marker + ")");
 }
}
 
class Cups {
 static Cup cup1;
 static Cup cup2;
 static {
 cup1 = new Cup(1);
 cup2 = new Cup(2);
 }
 Cups() {
 print("Cups()");
 }
}
 
public class ExplicitStatic {
 public static void main(String[] args) {
 print("Inside main()");
 Cups.cup1.f(99); // (1)
 }
 // static Cups cups1 = new Cups(); // (2)
 // static Cups cups2 = new Cups(); // (2)
}

출력:

Inside main()
Cup(1)
Cup(2)
f(99)


비정적 인스턴스 초기화
이것에 대해서는 별로 할 말이 없으며, 단지 일반적인 초기화이며 다음에서 실행됩니다. 순서대로 실행되며 여러 번 실행될 수 있습니다.

class Mug {
 Mug(int marker) {
 print("Mug(" + marker + ")");
 }
 void f(int marker) {
 print("f(" + marker + ")");
 }
}
 
public class Mugs {
 Mug mug1;
 Mug mug2;
 {
 mug1 = new Mug(1);
 mug2 = new Mug(2);
 print("mug1 & mug2 initialized");
 }
 Mugs() {
 print("Mugs()");
 }
 Mugs(int i) {
 print("Mugs(int)");
 }
 public static void main(String[] args) {
 print("Inside main()");
 new Mugs();
 print("new Mugs() completed");
 new Mugs(1);
 print("new Mugs(1) completed");
 }
}
rrree

Java의 정적 변수 초기화에 대한 전체 분석과 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.