Es handelt sich um eine späte Bindung, nicht um eine frühe Bindung. Frühes Binden geschieht nur bei nicht überschreibbaren Methoden.
Angesichts dieses Codes:
public class Test
{
void foo()
{
System.out.println("foo");
}
final void bar()
{
System.out.println("bar");
}
void car(String s)
{
System.out.println("car String");
}
void car(Object o)
{
System.out.println("car Object");
}
static void star()
{
System.out.println("star");
}
public static void main(final String[] argv)
{
Test test;
Object a;
Object b;
test = new Test();
a = "Hello";
b = new Object();
test.foo();
test.bar();
test.car(a);
test.car(b);
Test.star();
}
}
Das von mir verwendete javac erzeugt dies für main:
public static void main(java.lang.String[]);
Code:
0: new #9; //class Test
3: dup
4: invokespecial #10; //Method "<init>":()V
7: astore_1
8: ldc #11; //String Hello
10: astore_2
11: new #12; //class java/lang/Object
14: dup
15: invokespecial #1; //Method java/lang/Object."<init>":()V
18: astore_3
19: aload_1
20: invokevirtual #13; //Method foo:()V
23: aload_1
24: invokevirtual #14; //Method bar:()V
27: aload_1
28: aload_2
29: invokevirtual #15; //Method car:(Ljava/lang/Object;)V
32: aload_1
33: aload_3
34: invokevirtual #15; //Method car:(Ljava/lang/Object;)V
37: invokestatic #16; //Method star:()V
40: return
}
invokevirtual bedeutet späte Bindung, invokestatic und invokespecial bedeutet frühe Bindung.
Die Linie:
24: invokevirtual #14; //Methode bar:()V
verweist auf eine nicht überschreibbare Methode, so dass sie logischerweise invokespecial sein sollte. Der Laufzeit steht es anscheinend frei, die Änderung vorzunehmen, wenn die Klasse geladen wird (ich könnte mich irren, ich habe mich nicht so tief in die VM-Interna eingearbeitet, aber nach dem, was ich gelesen habe, scheint das der Fall zu sein).
Ihre Frage lautet also, warum Java nicht über das sogenannte Multiple Dispatch ( wikipedia link hier ), bei dem die Laufzeitumgebung entscheidet, welche Methode auf der Grundlage des Variablenwerts aufgerufen werden soll, anstatt auf der Grundlage des Variablenwerts, der deklariert wurde.
Der Compiler arbeitet so, dass er etwas sagt wie:
- Ich rufe SomeClass.doSomething auf einer Variablen, die als Objekt deklariert ist.
- Verfügt SomeClass über eine Methode namens doSomething, die ein Objekt annimmt?
- Wenn ja, dann geben Sie eine invokevirtual Aufruf zu dieser Methode aus.
Was Sie wollen, ist ein zusätzlicher Schritt, der zur Laufzeit passiert (er könnte nicht zur Kompilierzeit passieren), der sagt:
- Die Variable verweist auf eine Ganzzahl.
- Ich rufe die SomeClass.doSomething-Methode auf.
- Rufen Sie die beste Übereinstimmung von SomeClass.doSomething-Methode auf, die eine Ganzzahl, eine Zahl oder ein Objekt annimmt aufruft (je nachdem, was zuerst gefunden wird).
Java macht das zur Laufzeit nicht, sondern ruft einfach die Methode auf, die der Compiler für den Aufruf vorgesehen hat.
In Java können Sie den Mehrfachversand wie folgt simulieren .