2015-03-02 5 views
4

Хорошо известно, что компилятор Java извлекает значения постоянных полей из других классов во время компиляции. Полученный файл класса не содержит запись константного пула (любого типа) для таких констант.Сделать компилятор Java включать символическую константу поля ссылки в файле класса - возможно?

В: Может ли компилятор сказать, чтобы сделать именно это? (Oracle JDK 7 будет хорошо)

В качестве иллюстрации рассмотрим фрагмент кода out.println(some.other.class.FOO), который читает Foo (скажем, public static final int FOO = 1234) и выводит его. Я могу найти ссылки на println без проблем, но константа превращается в анонимную sipush 1234.

Для анализа зависимости на уровне класса было бы здорово иметь прозрачность здесь! Заметьте, что я не прошу внести какие-либо измененные значения там как-то появятся в зависимом коде (см. Множество других вопросов по этому вопросу) ...

Я подумываю о подключении API Java Compiler javac, но это звучит немного надуманно? Есть идеи?

+1

http://www.stackoverflow.com/questions/3524150/is-it-possible-to-disable-javacs-inlining-of-static-final-variables?rq=1 –

+0

Можете ли вы уточнить, что вам нужен компилятор? .. Я думаю, у меня может быть интересный ответ ... –

+0

Спасибо @ RC за другой указатель. Извините, что я пропустил это при поиске (и, вероятно, еще ...). @ Jean-François, идея состоит в том, чтобы каким-то образом создать синтетический (неиспользуемый) Fieldref (как для GETSTATIC opcodes) в Constant Pool. Я понимаю, что это будет только для * собственного * кода (требуется компиляция), но сохранит инструмент проверки дефрагментации, по крайней мере, на уровне класса, а не на уровне исходного кода. – mgaert

ответ

2

Только final variables initialized to constant expressions может быть настолько встроенным. Поэтому, если вы хотите избежать подобранного времени компиляции, очевидный подход заключается в том, чтобы сделать поле не final или сделать выражение инициализации достаточно сложным, чтобы оно больше не считалось постоянным (например, (null == null) ? 1234 : 0))  ¹.

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

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

+0

Не совсем верно. Если у вас есть нестатический final boolean с предварительно заданным значением, которое используется в условном выражении внутри одного класса, это значение также включено для удаления условного. Ради полноты. –

+0

@ Rafael Winterhalter: сайт использования не обязательно должен находиться в одном классе, независимо от того, является ли поле 'static' или нет. Конечно, это должно быть в случае 'private', но это также не зависит от флага' static'. И, между прочим, * каждая переменная 'final 'может быть константой времени компиляции, даже локальными переменными.(да, это означает, что если вы объявляете локальную переменную типа 'final int foo = 10;', вы можете использовать ее имя в следующем выражении 'switch' в качестве метки' case'). Похоже, это распространенное заблуждение думать, что оно ограничено полями 'static' (или полями вообще). – Holger

+0

@ Хольджер, вы правы, константы компиляции не имеют ничего общего с полями, поскольку они неявны из спецификации: (http://docs.oracle.com/javase/specs/jls/se7/html /jls-15.html#jls-15.28). Я попытался добавить что-то к ответу. В основном, я забыл о внутренних классах, поскольку я только предположил, что нестатические поля из других классов не будут иметь здесь никакого значения, поскольку они не могут быть отнесены к ним, не проходя через экземпляр этого класса, которые снова никогда не являются константами времени компиляции. Но вы правы, конечно. –