Как влияние метода/поля влияет на метод вложения в Java?
Случай, который я имею в виду, - это нечто вроде public
геттера для private
поля:
private Thing blah;
public Thing getBlah() {
return blah;
}
Здесь возникает несколько проблем.
Во-первых, делает ли сам компилятор Java какой-либо встраивание? На этот вопрос, кажется, отвечают по-разному, некоторые говорят " да", а некоторые говорят " нет". Я не знаю, было ли это потому, что он использовал, чтобы не делать какой-либо вставки, но теперь делает это, или это просто, что некоторые люди правы, а некоторые люди ошибаются...
Теперь, если это действительно делает некоторые inlining, я прав, думая, что он не может, возможно, inline getBlah()
вызывает? Они были бы очевидным местом для того, чтобы вложение было полезным, потому что метод очень прост, и накладные расходы на вызов метода имеют такой же размер, как и код самого метода. Но если он был встроен компилятором, вы получите байт-код, который напрямую обратился к private
полю; и, конечно же, JVM будет жаловаться? (Это применимо, даже если этот метод был static final
).
Во-вторых, как насчет компилятора JIT? Насколько я вижу, эта проблема не применяется, когда дело доходит до вложения на этом уровне. После создания собственного кода JVM уже выполнил свои проверки и подтвердил, что я могу вызвать метод (потому что он public
); поэтому он может затем генерировать собственный код, который встраивает вызов, без каких-либо проблем с видимостью... да?
Компилятор javac (и любой действительный java-компилятор) не будет и не сможет встроить геттеры; подумайте об этом: вы можете расширить класс из этого класса и перезаписать геттер. И да, если компилятор будет чрезмерно зависеть от того, что доступ к нему не будет проходить через верификатор (ну, по крайней мере, он не должен пропускать верификатор, но они не проверяют все). В java 1.3 вы даже можете сделать main() частным, и все равно работа... аналогичным образом в javac была опция -O, которая иногда винила ваш код).
JIT - это целый другой зверь; он знает (ну, по крайней мере, в наши дни) в любое время, если есть перегрузка для метода или нет. Даже если класс загружается позже, что перезаписывает геттер, он может деоптимизировать уже JIT'd методы, чтобы отменить изменения в дереве наследования (это одна из оптимизаций компиляторов AOT не имеет информации для).
Таким образом, он может безопасно встраивать все, что захочет. Также не нужно искусственно поддерживать modfiers доступа, потому что в скомпилированном машинном коде нет такой вещи, и снова он знает, что такое трансформация кода vaild (и поскольку геттеры настолько распространены, что это также низкий уровень висящих фруктов для JIT оптимизировать).
Изменение: Чтобы сделать это абсолютно ясно, в параграфах рассматриваются потенциально виртуальные методы; особенно те, которые не являются частными, статическими или окончательными. В некоторых случаях Javac мог выполнять inlining; потому что это может доказать, что для них не существует переопределения. Было бы бессмысленным обязательством перед лицом того, что JIT также делает это, и он намного лучше работает над этим.
javac
не использует встроенные методы, такие же простые, как getBlah()
и setBlah()
-XX:MaxInlineLevel
)public
и private
методам с точки зрения встраивания. Модификаторы доступа обычно не влияют на inlining, если не встречаются некоторые конкретные случаи.Независимо от того, какой-либо конкретный компилятор Java - например, Oracle - выполняет любую инкрустацию, - это деталь реализации, которую лучше было бы игнорировать. Будущее поколение вашего выбранного компилятора или альтернативного компилятора может работать иначе, чем тот, который вы сейчас просматриваете.
Однако, в отличие от компилятора Java, он мог встроить только private
методы и конструкторы. Все остальное является кандидатом на доступ из (непознаваемых) других классов.
С другой стороны, компилятор JIT может делать практически все, что он хочет, включая встраивание общедоступных методов. Он отвечает за любые корректировки, которые могут потребоваться при загрузке новых классов. Методы доступа в стиле фасонов - особенно вероятная вещь для оптимизации JIT, которая является такой общей моделью.
final
методе нет возможности перезаписать его в подклассе; но, что более важно, метод не обязательно должен быть всегда встроенным или никогда не встроенным. Компилятор мог видеть, что в этом конкретном контексте метод не был переопределен, и встроить его для этого вызова ... не так ли? Это не должно быть все или ничего.