2013-05-31 2 views
79
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 не выполняется.Статический блок в Java не выполнен

Почему это так? И если я удалю final, будет ли он работать нормально?

Какая память будет выделена первой, переменная static final или блок static?

Если из-за модификатора доступа final класс не загружается, тогда как переменная может получить память?

+1

Какова точная ошибка и сообщение, которое вы получите? – Patashu

+0

@Patashu, нет ошибки, его сомнение – Sthita

ответ

125
  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 загружается, как вы ожидаете, и выполняет его статический инициализатор.

+1

Но, как оценивается значение конечной переменной в классе без загрузки класса? –

+17

Вся оценка происходит во время компиляции, и конечный результат жестко закодирован во все места, которые ссылаются на переменную. –

+1

Итак, если вместо примитивной переменной это какой-то объект, тогда такое hardcoding будет невозможно. Не так ли? Итак, в этом случае, будет ли этот класс загружен, а статический блок будет выполнен? –

0

Насколько я знаю, он будет выполнен в порядке появления. Например:

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» фактически используется и «выполнено» в другой части код (мой случай я сделал «новый Statique()».

+2

Вы получаете этот результат, потому что вы загружаете класс 'Statique', выполняя' new Statique() '. В заданном вопросе класс «Mno» вообще не загружается. – RAS

+0

@RAS u абсолютно прав ... Mno не загружен. – Sthita

+0

@Fabyen, если я создаю объект Mno в тестовом классе следующим образом: Mno anc = New Mno(); то его прекрасный, но текущий сценарий я этого не делаю, сомневаюсь, что если я удаляю final, тогда статический блок выполняет штраф, иначе он не будет выполняться, почему так? – Sthita

7

причина, почему класс не загружается, что VAL является finalи она инициализируется с a constant expression (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; } 
    
5

Если вы видите генерироваться байткодом с помощью javap -v Test.class, основной() выходит как:

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); 
    } 
} 
1

1) На самом деле вы не распространяется, что Mno класс поэтому при компиляции запуска он будет генерировать постоянную переменную VAL и когда начать выполнение, когда эта переменная необходима для ее загрузки из памяти. Также не требуется ссылка на класс, чтобы статический bock не выполнялся.

2) если класс A расширяет этот класс Mno в то время, когда статический блок включен в класс A, если вы это сделаете, тогда выполняется статический блок. например .. общественного класса А продолжается 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); 
    } 
} 
Смежные вопросы