[Java] inline methods
А может ли хороший Java-компилятор(например, Sun-овский) инлайнить статические методы?эээ... а зачем?
2. А может ли хороший джавер объяснить, в чём разница между подстановкой тела статического и нестатического метода?
Геттеры-сеттеры могут легко инлайниться.
Представляешь !
Например, в С++ виртуальные функцмии не инлайнятся(по-моему зато обычные могут инлайниться. Думаю, что также дела должны обстоять и в Java. Только не знаю, как проверить, инлайнился метод или нет?
2. А может ли хороший джавер объяснить, в чём разница между подстановкой тела статического и нестатического метода?Разница в том, что не статический метод может быть переопределен и у компилера могут быть трудности в выборе рализации для инлайна, а статический метод не переопределяется и таких трудностей не возникает.
Хороший форумчанин уже пользовался Google и дажен набирал там java inline methodsСлАбо. Возьми частные уроки пользования Google. Уже на первой странице можно найти ссылку (даже две) на http://blogs.sun.com/ahe, а там написано (можно Ctrl+F на "inline"):
Представляешь !
...On the other hand, many static optimizers will automatically inline method calls. The fundamental problem with inlining method calls is that if the inlined method was never called by method into which it was inlined it will just make the resulting method bigger (and perhaps prevent it from being inlined in other methods). So although a static optimizer think it is optimizing it has no data about how the program behaves at runtime and may make mistakes.
This is a fundamental problem that will make your programs run slower on HotSpot. The name HotSpot comes from the VM's ability to recognize hotspots in the program based on statistics collected while the program is running. By using this data, HotSpot can generally make better decisions than a static optimizer.
Besides hurting HotSpots ability to inline based on live data, big methods resulting from premature inlining can have other negative effects on performance. HotSpot will compile hot methods to native machine code. This code is sensitive to CPU level optimizations such as code caches and branch prediction. I don't know if this is a real life problem...
---
Т.е. ответ на твой исходный вопрос - может.
статический метод не переопределяетсяДаже не знаю, что тебе ответить, то ли "наглая ложь" (KOHTPA style то ли "я бы за такое сразу банил" (чья-то подпись, мне очень нравится).
Вот ещё кусочек текста с трепом про то, как посмотреть, инлайнился метод, или нет.
Насколько я помню, в Java компилятор очень простой (тупой а оптимизации возложены на VM. Соответственно JVM может инлайнить методы, какие сочтет подходящими. Подозреваю, что точно узнать, как VM решает, инлайнить или нет, можно только изучив исходники VM. Можешь попробовать, благо они открыты.
to . Хочешь сказать, что в Jave статические методы переопределяются?
ста с трепом про то, как посмотреть, инлайнился метод, или нет.Это я читал. Только, когда я запускаю этот профайлер, иногда в логе я не вижу ни одного вызова своих методов. Даже main.
я не вижу ни одного вызова своих методов. Даже main
Печально. А откуда такой интерес именно к подстановке статических методов? Если просто надо производительность конкретного приложения улучшить, возьми хороший профайлер, JProfiler, например.
![](/images/graemlins/lol.gif)
to .Это я просёк, почти сразу после того, как прочел в заголовке поста "[re:]".
Хочешь сказать, что в Jave статические методы переопределяются?Видишь ли, у меня никак не доходят руки до "How to Become a Bydlo-coder in 24 Hours. Advanced Techniques and Strategies" ("Thinking in C++" дочитать бы когда-нибудь сначала... поэтому я всё ещё проверяю сомнительные утверждения самостоятельно. Особенно такие, на которые требуется 1-2 минуты.
Печально. А откуда такой интерес именно к подстановке статических методов? Если просто надо производительность конкретного приложения улучшить, возьми хороший профайлер, JProfiler, например.Меня тоже смущает такой интерес к inline. По ходу в человеке бунтует C-шное прошлое
Просто стало интересно.
afaik, static-метод перекрыть(override) нельзя, можно только скрыть (hide).
hide, в отличии от override, на оптимизацию никак не влияет, т.к. еще на этапе компиляции известно какой метод будет вызываться.
ps
поправил, ранее неправильно было указано overload вместо override
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class Base {
static void method {
System.out.println("From Base");
}
}
class Derived extends Base {
static void method {
System.out.println("From Derived");
}
}
public class Test {
public static void main(String[] args) throws Exception {
List list = new ArrayList;
list.add(new Base;
list.add(new Derived;
for (Iterator iter = list.iterator; iter.hasNext;) {
Base item = (Base) iter.next;
Method method = item.getClass.getDeclaredMethod("method", new Class[0]);
method.invoke(null, new Object[0]);
}
}
}
Method method = item.getClass.getDeclaredMethod("method", new Class[0]);1. какое это имеет отношение к обсуждаемой теме? а именно к Jit-оптимизации и inline-у?
method.invoke(null, new Object[0]);
2. почему ты это называешь перекрытием (override-ингом)?
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.
1. какое это имеет отношение к обсуждаемой теме? а именно к Jit-оптимизации и inline-у?Женские приёмы ведения дискуссии в разделе Programming?
![](/images/graemlins/smile.gif)
2. почему ты это называешь перекрытием (override-ингом)?Я таких умных слов-то не знаю.
![](/images/graemlins/smile.gif)
Хочешь сказать, что в Jave статические методы переопределяются?Я дал ответ, точнее пример, без всяких так AFAIK, "according to ОБС Consulting Ltd." и т.д.
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.5 раз прочитал, ничего не понял. Даже попробовал подумать. Не получается. Что сия фраза значит?.. Какое отношение имеет к вопросу переопределения статических функций.
Хочешь сказать, что в Jave статические методы переопределяются?Это не переопределение, имхо. Обычно, когда говорят по-русски "переопределение", имеется виду именно override, по крайней мере я всегда так это понимал и меня всегда так понимали. То что ты привел в примере - это замещение.
![](/images/graemlins/smile.gif)
class A
{
public virtual void Method
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Method
{
Console.WriteLine("B");
}
}
A a = new B;
При переопределении(override) метода базового класса вызов a.Method напечатает B, если вместо override написать new - это замещение и вызов a.Method - напечатает A, хотя a - инстанс класса B. Это называется полиморфизм.
Соответственно, у статических методов может быть только замещение.
у статических методов может быть только замещениеПример мой запускал?
На всякий случай, выдаёт он следующее:
From Base
From Derived
Нет, а без рефлекшена будет работать?
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
Хотя интересная особенность явы. Ща на шарпе попробую
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
![](/images/graemlins/smile.gif)
Там же ты берешь getClass Вот он и возвращает КОНКРЕТНЫЙ класс. У которого вызывается конкретный метод.
Переопределение(override) - имхо термин корректен в случае инстансов классов. Так что тут уже терминологичесий спор
![](/images/graemlins/smile.gif)
А override это из C#, где тому, что с методами у Джава по умолчанию, в C# соответствует вариант, который явно обозначается ключевым словом override. И наоборот, семантика с методами, что по умолчанию в C#, получается в Java, когда используется final. Таким образом, final позволяет инлайнить на этапе компиляции. Хотя тут JVM по идее генерирует код в рантайме, когда известны все подклассы данного класса, для которых создавались объекты, и JVM может проверить тот факт, что виртуальный вызов не нужен.
А так поддерживаю предыдущие высказывания о том, что не стоит на эту тему особенно напрягаться. Не так это принципиально, и оптимизировать можно потом, там где это необходимо. Главное, чтобы программа позволяла относительно легко корректировать реализацию отдельных фрагментов независимо от остального кода.
Имхо лучше основное внимание по производительности уделять размещению объектов/данных в памяти, чтобы сборщик мусора не нагружать сильно. За этим лучше следить сразу, так как переход от коллекций к массивам и переход от объектов к базовым типам нельзя назвать прозрачным, и это часто приводит серьезной правке кода.
override - это термин любого OOP-языка.
в C# - override дополнительно зафиксирован как ключевое слово
google: java override method
google: c++ override method
google: smalltalk override method
можно еще какую-нибудь wikipedia-ю почитать
http://en.wikipedia.org/wiki/Method_overriding_%28programmin...
Согласен, только в отличии от Java в C# методы можно не только переопределять, но и перекрывать — этому нужно эти понятия явно отделять. В Java имхо можно вообще другими словами обходиться, например: задать для метода m другую реализацию, которая ...
Я не совсем понял, что хотел своим фрагментом кода показать. Там не запуская ясно, какой будет вывод, и о чем это свидетельствует.
ты этим гордишься?
> Я дал ответ, точнее пример, без всяких так AFAIK, "according to ОБС Consulting Ltd." и т.д.
ты дал хреновый пример, который что-то выдает, при чем ты даже не можешь себе объяснить как он работает, и почему это не перекрытие методов.
я правильно понимаю, что, по-твоему вот это тоже перекрытие метода:
using System;
using System.Collections.Generic;
using System.Text;
namespace Overriding
{
class A
{
}
class B
{
}
class MyBaseClass
{
public static void Method(A a)
{
Console.WriteLine("from A");
}
}
class MySuperClass
{
public static void Method(B a)
{
Console.WriteLine("from B");
}
}
class Program
{
static void Main(string[] args)
{
object[] items = new object[] { new A new B };
foreach (object item in items)
{
foreach (Type type in typeof(Program).Assembly.GetTypes
{
foreach (System.Reflection.MethodInfo method in type.GetMethods(
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
{
System.Reflection.ParameterInfo[] parameters = method.GetParameters;
if (parameters.Length > 0 && parameters[0].ParameterType == item.GetType
method.Invoke(null, new object[] { item });
}
}
}
}
}
}
программа на выходе выдает
from A
from B
Выделение мое.
13.4.22 Method and Constructor Body
Changes to the body of a method or constructor do not break compatibility with pre-existing binaries.
We note that a compiler cannot expand a method inline at compile time.
The keyword final on a method does not mean that the method can be safely inlined; it means only that the method cannot be overridden. It is still possible that a new version of that method will be provided at link time. Furthermore, the structure of the original program must be preserved for purposes of reflection.
In general we suggest that implementations use late-bound (run-time) code generation and optimization.
И как правильно отметил , компиляторы Java обычно досаточно просты, большая часть оптимизации отдается на откуп машине Java. Кроме того, формат байт-кода позволяет выполнять inlining не только статических, но и "виртуальных" методов (Sun HotSpot JVM так вроде бы делает). Если в рантайме не имеется наследников класса, JVM может агрессивно inlinить вызовы виртуальных методов. Когда загружается наследник этого класса JVM может выполнять обратное преобразование (т.е. заменять inlineный вызов или вызов, скомпилированный в машинный код, обратно на байт-код и интерпретировать его).
public class MainExc {
private static class Base{
public static void method{
System.out.println("Base");
}
}
private static class Derived extends Base{
public static void method{
System.out.println("Derived");
}
}
public static void main(String[] args) throws Exception{
Base example = new Derived;
example.method;
Derived)example).method;
}
}
И резалт:
Base
Derived
Значит вызываемый метод дейсвительно раранее известен.
Плюс нельзя сделать static abstract.
From BaseИменно потому что item.getClass разные. Это ничего не доказывает.
From Derived
1. Опровергнуть, что статические методы нельзя переопределить (если к ним вообще применимо такое понятие).
2. Поприкалываться (как всегда
![](/images/graemlins/smile.gif)
Я выдал, можно сказать, задачу-шутку (про которую, как мне сказали, я не знаю, как она работает
![](/images/graemlins/grin.gif)
В ответ получил... э-э... целый букет ответов. Что ж, лучше узнал некоторых форумчан.
![](/images/graemlins/smile.gif)
2е .... хз, шутки не понял.
Если ты знал, что пишешь фигю, зачем вводить людей в заблуждение?
2. Показать немного интересную (ну, с моей быдлокодерской точки зрения) задачу. Этот пример я придумал, когда здесь шло обсуждение т.н. виртуальных статических методов.
тогда, странно, что ты не понял, что такое "связывание по имени"
получается, что ты фактически не чувствуешь одну из важных разниц между компилятором и интерпретатором.
как действует obj.method - узнаём класс obj и запускаем его метод для объекта obj
Ну, то есть может и как-то по-другому, но жто было бы логично с точки зрения хранения.
Тогда точно таким же методом можно было бы вызывать статические методы. Но увы, класс там
не определяется, а юзается объявленный
> про которую, как мне сказали, я не знаю, как она работаетТы можешь говорить внятно? Типа "связывание по имени - это то-то. Например, то-то. В данном случае - вот".
тогда, странно, что ты не понял, что такое "связывание по имени"
получается, что ты фактически не чувствуешь одну из важных разниц между компилятором и интерпретатором.
А то я что-то не пойму, если это откомпилировать gcj, это перестанет работать?
![](/images/graemlins/smile.gif)
Ну, то есть может и как-то по-другомуДа не, всё правильно. JVM-инструкция invokestatic с указанием имени класса, метода (а также аргументов и возвращаемого значения).
А ещё некоторые думают, что в Java каждый не-private не-final метод - виртуальныйА что есть не виртуальные не статические методы в Java? Как private связан с виртуальностью тоже интересно.
при static-е: сразу в точке вызова запоминается адрес метода
при виртуале: запоминается адрес из vtable-а
по имени: в точке вызова запоминается в виде строки название метода
соответственно первый метод самый быстрый, т.к. сразу делается переход.
второй в два раза медленнее - т.к. делается два "перехода".
по имени - где-то на несколько порядков медленнее, т.к. делается линейный, двоичный или хэш поиск нужного метода по строке.
А что есть не виртуальные не статические методы в Java? Как private связан с виртуальностью тоже интересно.Конструкторы.
private-метод не может быть виртуальным, если я ничего не путаю.
Ну тогда в Java все связывания по имени, если я ничего не путаю. Достаточно продизассемблировать Java-код (.class-файл, javap с какими-то ключами но у меня на домашнем компе нет Java (!).
так вот я и говорю, что ты ни фига не понимаешь, чем, например, invokestatic A/method отличается от a.GetType.GetDeclaringMethod("method").invoke.
нет там никаких имен, есть только ссылка на "дескриптор"
In bytecode, after the invokestatic opcode is a 16-bit unsigned integer index. This is the index of an entry in the constant pool. The entry is tagged as a CONSTANT_Methodref entry. This entry has two fields. One field points to a CONSTANT_Class entry in the constant pool whose name is the classname from <method-spec>, and the other points to a CONSTANT_NameAndType entry in the constant pool whose name is the methodname from <method-spec> and whose descriptor is the type descriptor from <method-spec>.http://www.cat.nyu.edu/~meyer/jvmref/ref--34.html
нет там никаких имен, есть только ссылка на "дескриптор".Я не понимаю, в чём принципиальная разница между именем и дескриптором имени. Ну не писать же всё время в байт-коде java.lang.String, java.lang.String, java.lang.String, java.lang.String, ... Проще использовать номерок в пуле констант.
In bytecode, after the invokestatic opcode is a 16-bit unsigned integer index. This is the index of an entry in the constant pool. The entry is tagged as a CONSTANT_Methodref entry. This entry has two fields. One field points to a CONSTANT_Class entry in the constant pool whose name is the classname from <method-spec>, and the other points to a CONSTANT_NameAndType entry in the constant pool whose name is the methodname from <method-spec> and whose descriptor is the type descriptor from <method-spec>.
И хватить давить меня примерами из C#. Ну не знаю я его.
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.
создай два package-а
один
class A
{
public void Method(double a)
{
Console.WriteLine("double a");
}
}
второй
class B
{
public static void Main
{
new A.Method(1);
}
}
собери их
далее поменяй первый package на:
class A
{
public void Method(int a)
{
Console.WriteLine("int a");
}
}
пересобери только его, и подсунь под старособранный второй package.
запусти, и запости в форум результат.
Конструкторы.Да ну тебя.
private-метод не может быть виртуальным, если я ничего не путаю.
?
это не фича языка, потому что про такой твой вызов язык ничего не знает, соответственно не прооптимизировать, ни проверить такой вызов - язык не может.
выполни кстати следующее упражнениеА зачем?
![](/images/graemlins/smile.gif)
И опять на C#. Нету у меня C#. Нету. И я его не знаю.
На Java, наверно, будет Error насчёт отсутствия нужного метода в .class-файле.
на Java-е код один в один такой же
public class Test1 {
private void m {
System.out.println("Test1");
}
public static class Test2 extends Test1 {
private void m {
System.out.println("Test2");
}
}
public static void main(String[] args) {
Test1 test1 = new Test2;
test1.m;
}
}
Выводит Test1.
Конструктор не хочу считать методом.
И ещё ты так и не пояснил фразуДля вызова метода с именем, которое берется из строки, в языке Java нет специальной поддержки. Все делается с помощью системных классов.
В ответ на:
вообще-то, это всегда называлось связыванием по имени, и к возможностям языка никакого отношения не имеет.
при связывании по имени - можно написать, например, вот так:
псевдокод
string className="A";
string method = "method";
invokestatic className+method;
дескриптор же жестко подразумевает, что название метода фиксированное (известное на этапе компиляции).
правильно, потому что компилятор разрезолвил вызов и сформировал в точке вызова дескриптор A/method (double а VM уже работает именно с этим дескриптором, и соответственно обижается, когда по этому дескриптору не получается найти метод.
еще интереснее сначала сделать метод
int Method{return 1;}
а потом заменить на
double Method{return 1;}
то можно увидеть, что дескриптор в том числе завязывается и на возвращаемое значение, хотя, например, тот же GetDeclaringMethod возвращаемым значением не интересуется.
было
public class A
{
public class Inner
{
public static void Method
{
Console.WriteLine("A.Inner.Method");
}
}
}
public class B:A
{
}
стало
public class A
{
}
public class B:A
{
public class Inner
{
public static void Method
{
Console.WriteLine("B.Inner.Method");
}
}
}
вызов
class Program
{
static void Main(string[] args)
{
B.Inner.Method;
}
}
Оставить комментарий
Sanjaz
А может ли хороший Java-компилятор(например, Sun-овский) инлайнить статические методы?