2016-12-25 7 views
2

Я создал небольшой класс Java и выполнил команду javap против соответствующего файла .class. Я просто делаю это, чтобы понять, как организован файл класса (да, я тоже проходил спецификации JVM). Я мог ошибаться, но из того, что я понимаю в структуре файла классов. кажется, что статический блок на уровне класса отображается как метод.Являются ли статические блоки на уровне класса представленными как методы в байтовом коде?

Я правильно интерпретирую это (что статический блок представляется как метод)? Если да, то статический блок каким-то образом считается эквивалентным методу в Java?

Исходный файл:

package test; 

public class TestClass 
{ 
    static { 
     System.out.println("abcd"); 
    } 

    public void method(String s) 
    { 
     System.out.println("hello world"); 
    } 
} 

javap выход:

Classfile /C:/TestClass.class 
    Last modified Dec 25, 2016; size 477 bytes 
    MD5 checksum 7571c8f98e814fb8bb53885f073c6048 
    Compiled from "TestClass.java" 
public class test.TestClass 
    minor version: 0 
    major version: 52 
    flags: ACC_PUBLIC, ACC_SUPER 
Constant pool: 
    #1 = Methodref   #7.#17   // java/lang/Object."<init>":()V 
    #2 = Fieldref   #18.#19  // java/lang/System.out:Ljava/io/PrintStream; 
    #3 = String    #20   // hello world 
    #4 = Methodref   #21.#22  // java/io/PrintStream.println:(Ljava/lang/String;)V 
    #5 = String    #23   // abcd 
    #6 = Class    #24   // test/TestClass 
    #7 = Class    #25   // java/lang/Object 
    #8 = Utf8    <init> 
    #9 = Utf8    ()V 
    #10 = Utf8    Code 
    #11 = Utf8    LineNumberTable 
    #12 = Utf8    method 
    #13 = Utf8    (Ljava/lang/String;)V 
    #14 = Utf8    <clinit> 
    #15 = Utf8    SourceFile 
    #16 = Utf8    TestClass.java 
    #17 = NameAndType  #8:#9   // "<init>":()V 
    #18 = Class    #26   // java/lang/System 
    #19 = NameAndType  #27:#28  // out:Ljava/io/PrintStream; 
    #20 = Utf8    hello world 
    #21 = Class    #29   // java/io/PrintStream 
    #22 = NameAndType  #30:#13  // println:(Ljava/lang/String;)V 
    #23 = Utf8    abcd 
    #24 = Utf8    test/TestClass 
    #25 = Utf8    java/lang/Object 
    #26 = Utf8    java/lang/System 
    #27 = Utf8    out 
    #28 = Utf8    Ljava/io/PrintStream; 
    #29 = Utf8    java/io/PrintStream 
    #30 = Utf8    println 
{ 
    public test.TestClass(); 
    descriptor:()V 
    flags: ACC_PUBLIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 
     LineNumberTable: 
     line 3: 0 

    public void method(java.lang.String); 
    descriptor: (Ljava/lang/String;)V 
    flags: ACC_PUBLIC 
    Code: 
     stack=2, locals=2, args_size=2 
     0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: ldc   #3     // String hello world 
     5: invokevirtual #4     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     8: return 
     LineNumberTable: 
     line 11: 0 
     line 12: 8 

    static {}; 
    descriptor:()V 
    flags: ACC_STATIC 
    Code: 
     stack=2, locals=0, args_size=0 
     0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: ldc   #5     // String abcd 
     5: invokevirtual #4     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     8: return 
     LineNumberTable: 
     line 6: 0 
     line 7: 8 
} 
SourceFile: "TestClass.java" 
+1

Разборка выглядит убедительно для меня. Почему вы считаете, что это не будет эквивалентно методу? Он ведет себя как метод «static void». Вы пытались скомпилировать блок инициализатора элемента (например, нестатический инициализатор), чтобы узнать, что это делает? Помните, что StackOverflow НЕ является дискуссионным сайтом. –

+0

@JimGarrison это действительный и полезный вопрос – firephil

+0

@firephil Не совсем, ответ - деталь реализации. Важно то, что спецификация языка содержит семантику блока инициализатора. Нигде он не заявляет, что он должен быть реализован как «метод», только то, что код выполняется в определенной точке в создании класса или объекта. Ответ, который говорит «да» для Java 8 сегодня, может быть «нет» в Java 9 или Java 10. Кроме того, знание текущего ответа не предоставляет никакой информации, которую вы могли бы использовать для принятия решения о вашей кодировке. –

ответ

0

Это не совсем метод, это инициализатор, как конструктор, но на уровне класса. «Статический блок» - не правильный термин; это «статический блок инициализатора», поэтому имеет смысл. Это как много или мало похоже на метод void как конструктор.

2

В Java, экземпляре и статике есть два типа инициализаторов.

На уровне байткода все статические инициализаторы (плюс инициализация статических полей, которые являются нефинальными или инициализированы неконстантным выражением) скомпилированы и объединены в один метод, который называется <clinit>. Это специальный метод, который автоматически вызывается JVM после загрузки класса, но не может быть вызван нормальным кодом. Обратите внимание, что независимо от того, сколько отдельных блоков статического инициализатора у вас на уровне исходного кода, существует только один метод клиницита.

Установщики экземпляра не имеют прямого эквивалента в байтекоде. Все инициализаторы экземпляров, а также инициализаторы полей экземпляров, компилируются и вставляются в методы конструктора классов сразу после возврата из вызова конструктора суперкласса. Кстати, это означает, что можно наблюдать состояние экземпляра до запуска инициализаторов, поэтому вы не должны вызывать виртуальные методы из конструктора.

 Смежные вопросы

  • Нет связанных вопросов^_^