Что означает «статический синтетический»? - PullRequest
25 голосов
/ 07 марта 2011

Я смотрю на некоторый дизассемблированный код, полученный из байт-кода Java. Я вижу некоторые заявления следующим образом:

.method static synthetic access$0()Lcom/package/Sample;

Я не могу понять, что означают synthetic или access$0. Может кто-нибудь помочь мне понять эту часть?

Ответы [ 3 ]

31 голосов
/ 07 марта 2011

На языке Java внутренние классы могут получать доступ к закрытым членам своего включающего класса. Однако в байт-коде Java концепция внутренних классов не существует, а закрытые члены недоступны. Чтобы обойти это, компилятор создает синтетические методы доступа во внешнем классе. Я считаю, что это то, что вы видите здесь. access$0 - это просто название метода. Я не уверен, что, если что-то делает synthetic. Он может просто скрыть метод от других компиляторов для обеспечения инкапсуляции.

26 голосов
/ 07 марта 2011

Синтетическое поле , (2)

поле, созданное компилятором , которое связывает локальный внутренний класс с локальной переменной блока или параметром ссылочного типа.

См. Также The JavaTM Virtual Machine Specification (§4.7.6) или Синтетический класс в Java .

4 голосов

assert оператор JDK 1.8 тематическое исследование

Оператор assert является примером конструкции, которая генерирует поле static synthetic в Oracle JDK 1.8.0_45:

public class Assert {
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

в основном компилируется в:

public class Assert {
    // This field is synthetic.
    static final boolean $assertionsDisabled =
        !Assert.class.desiredAssertionStatus();
    public static void main(String[] args) {
        if (!$assertionsDisabled) {
            if (System.currentTimeMillis() != 0L) {
                throw new AssertionError();
            }
        }
    }
} 

Это можно проверить с помощью:

javac Assert.java
javap -c -constants -private -verbose Assert.class

, который содержит:

    static final boolean $assertionsDisabled;
  descriptor: Z
  flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

Синтетическое полесгенерированный так, что Java должен вызывать Assert.class.desiredAssertionStatus() только один раз во время загрузки, а затем кэшировать результат там.

См. также: https://stackoverflow.com/a/29439538/895245 для более подробного объяснения.

Обратите внимание, что это синтетическое поле может генерировать конфликты имен с другими полями, которые мы можем определить.Например, в Oracle JDK 1.8.0_45 не удается скомпилировать следующее:

public class Assert {
    static final boolean $assertionsDisabled = false;
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

Единственное, что «мешает», - это соглашение об именовании, не использующее доллары в ваших идентификаторах.См. Также: Когда мне следует использовать символ доллара ($) в имени переменной?

Бонус:

static final int $assertionsDisabled = 0;

будет работать, поскольку в отличие от Java байт-коддопускает несколько полей с одинаковыми именами, но разными типами: Переменные с одинаковыми именами, но с разными типами

...