Вероятно, самый прямой способ понять , почему вам необходимо неявно передавать ссылку this
на каждую нестатическую функцию, которую вы вызываете, чтобы показать вам, как такой вызов функции работает «под капотом»..
Давайте рассмотрим простой пример, например
class Test {
public void foo(int arg) {}
public static void bar(int arg) {}
public void baz() {
foo(1);
bar(2);
}
}
В чем разница между foo
и bar
?
Нестатическая функция foo
выполняется вконтекст объекта, в то время как у статического bar
такого контекста нет.Это означает, что foo
сможет читать и записывать любые поля внутри этого объекта, bar
не будет.
В то время как Java как язык знает о контексте любой функции, которую вы вызываете, виртуальная машина Java(JVM), которая на самом деле выполняет код, напрямую не различает статические и нестатические функции и не знает контекстов вызовов.(Да, это немного вопрос семантики, поскольку он различает статическое и динамическое связывание, которое в основном совпадает со статическими / нестатическими функциями)
Поэтому, когда вы вызываете нестатический метод,контекст вызова (т. е. объект, для которого вызывается метод) должен быть предоставлен как неявный параметр, который называется this
.
Байт-код JVM для приведенного выше примера будет следующим:
public void baz();
Code:
0: aload_0 // Push 'this' as the first parameter onto the stack
1: iconst_1 // Push 1 as the second parameter onto the stack
2: invokevirtual #2 // Call 'foo'
5: iconst_2 // Push 2 as the first parameter onto the stack
6: invokestatic #3 // Call 'bar'
9: return
Вы видите, что для статической функции вы только помещаете параметр в стек (который затем извлекается последующим вызовом), для нестатических функций вы сначала помещаете this
в стек, которыйбыл также первым аргументом вызова функции baz
(aload
обозначает аргумент load )