[java] Java의 정적 블록이 실행되지 않음
class Test {
public static void main(String arg[]) {
System.out.println("**MAIN METHOD");
System.out.println(Mno.VAL); // SOP(9090);
System.out.println(Mno.VAL + 100); // SOP(9190);
}
}
class Mno {
final static int VAL = 9090;
static {
System.out.println("**STATIC BLOCK OF Mno\t: " + VAL);
}
}
static
클래스가로드 될 때 블록이 실행 된다는 것을 알고 있습니다. 그러나이 경우에는 인스턴스 변수의 내부 클래스 Mno
입니다 final
때문에 그의,static
블록은 실행되지 않는다.
왜 이렇게이다? 을 제거하면 final
제대로 작동합니까?
어떤 메모리가 먼저 할당 됩니까 , static final
변수 또는 static
블록?
받는 사람에 의한 경우 final
액세스 수정 클래스는로드되지 않습니다, 그럼 어떻게 변수 GET 메모리 할 수 있습니까?
답변
static final int
필드는 인 컴파일 시간 상수 와 그 값이 원점에 대한 참조없이 대상 클래스로 하드 코딩되고;- 따라서 메인 클래스는 필드를 포함하는 클래스의 로딩을 트리거하지 않습니다.
- 따라서 해당 클래스의 정적 초기화 프로그램은 실행되지 않습니다.
구체적으로 컴파일 된 바이트 코드는 다음과 같습니다.
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(9090)
System.out.println(9190)
}
제거하자마자 final
더 이상 컴파일 타임 상수가 아니며 위에서 설명한 특수 동작이 적용되지 않습니다. Mno
클래스는 예상대로로드 및 실행하는 초기화 정적된다.
답변
클래스가로드되지 않은 이유 VAL
는 final
AND 가 상수 표현식 (9090)으로 초기화되기 때문입니다 . 이 두 조건이 충족되는 경우에만 상수가 컴파일 시간에 평가되고 필요한 경우 “하드 코딩”됩니다.
컴파일 타임에 표현식이 평가되는 것을 방지하고 JVM이 클래스를로드하도록하려면 다음 중 하나를 수행 할 수 있습니다.
-
마지막 키워드를 제거하십시오.
static int VAL = 9090; //not a constant variable any more
-
또는 오른쪽 표현식을 상수가 아닌 것으로 변경합니다 (변수가 여전히 최종인 경우에도).
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
답변
를 사용하여 생성 된 바이트 코드를 javap -v Test.class
보면 main ()이 다음과 같이 나옵니다.
public static void main(java.lang.String[]) throws java.lang.Exception;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String **MAIN METHOD
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: sipush 9090
14: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: sipush 9190
23: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
26: return
11: sipush 9090
Mno.VAL은 컴파일 시간 상수이기 때문에 정적 최종 값이 직접 사용된다는 것을 ” ” 에서 명확하게 볼 수 있습니다 . 따라서 Mno 클래스를로드 할 필요가 없습니다. 따라서 Mno의 정적 블록은 실행되지 않습니다.
아래와 같이 Mno를 수동으로로드하여 정적 블록을 실행할 수 있습니다.
class Test{
public static void main(String arg[]) throws Exception {
System.out.println("**MAIN METHOD");
Class.forName("Mno"); // Load Mno
System.out.println(Mno.VAL);
System.out.println(Mno.VAL+100);
}
}
class Mno{
final static int VAL=9090;
static{
System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
}
}
답변
-
실제로 Mno 클래스를 확장하지 않았으므로 컴파일이 시작될 때 변수 VAL의 상수를 생성하고 해당 변수가 필요할 때 실행이 시작될 때 메모리에서로드됩니다. 따라서 정적 bock이 실행되지 않도록 클래스 참조가 필요하지 않습니다.
-
class가 class를
A
확장Mno
하면 정적 블록이 클래스에 포함됩니다.A
이렇게하면 해당 정적 블록이 실행됩니다. 예를 들어 ..public class A extends Mno { public static void main(String arg[]){ System.out.println("**MAIN METHOD"); System.out.println(Mno.VAL);//SOP(9090); System.out.println(Mno.VAL+100);//SOP(9190); } } class Mno { final static int VAL=9090; static { System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); } }
답변
내가 아는 한, 그것은 출현 순서대로 실행될 것입니다. 예 :
public class Statique {
public static final String value1 = init1();
static {
System.out.println("trace middle");
}
public static final String value2 = init2();
public static String init1() {
System.out.println("trace init1");
return "1";
}
public static String init2() {
System.out.println("trace init2");
return "2";
}
}
인쇄됩니다
trace init1
trace middle
trace init2
방금 테스트하고 “Statique”클래스가 실제로 사용되고 다른 코드에서 “실행”될 때 정적이 초기화 (=> print)됩니다 (제 경우에는 “new Statique ()”를 수행했습니다.).