[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 메모리 할 수 있습니까?



답변

  1. static final int필드는 인 컴파일 시간 상수 와 그 값이 원점에 대한 참조없이 대상 클래스로 하드 코딩되고;
  2. 따라서 메인 클래스는 필드를 포함하는 클래스의 로딩을 트리거하지 않습니다.
  3. 따라서 해당 클래스의 정적 초기화 프로그램은 실행되지 않습니다.

구체적으로 컴파일 된 바이트 코드는 다음과 같습니다.

public static void main(String arg[]){
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

제거하자마자 final더 이상 컴파일 타임 상수가 아니며 위에서 설명한 특수 동작이 적용되지 않습니다. Mno클래스는 예상대로로드 및 실행하는 초기화 정적된다.


답변

클래스가로드되지 않은 이유 VALfinal 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 9090Mno.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);
    }
}


답변

  1. 실제로 Mno 클래스를 확장하지 않았으므로 컴파일이 시작될 때 변수 VAL의 상수를 생성하고 해당 변수가 필요할 때 실행이 시작될 때 메모리에서로드됩니다. 따라서 정적 bock이 실행되지 않도록 클래스 참조가 필요하지 않습니다.

  2. 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 ()”를 수행했습니다.).


답변