Podczas gdy główną zasadą polimorfizmu jest oddzielenie "tego, od kogo" pod kątem types
, ale co wprowadza mnie w zakłopotanie, w jaki sposób mechanizm wywoływania metody dowiaduje się i nazywa prawidłowe ciało metody w polimorfizmie.W jaki sposób metoda Java Determine wywołuje w środowisku wykonawczym polimorfizm?
Ponieważ w Javie wszystkie metody wiązania jest late-binding
chyba że metoda jest static
, final
lub private
i późno wiążącego odbywa się przez JVM które precomputes method table
dla każdej klasy, a następnie zrobić stół patrzeć podczas wykonywania w normalnym wywołaniu metody.
Ale to samo dzieje się podczas polimorfizmu. Na przykład
Załóżmy Mam Generic klasy Cycle
z ride()
metody
class Cycle {
public void ride(){
System.out.println("I'm Riding generic Cycle()");
}
}
i mam trzy klasy specjalistyczne Bicycle
Tricycle
i Unicycle
która rozciąga Generic klasy Cycle
i nadpisuje jego metodę ride()
.
class Bicycle extends Cycle {
public void ride() {
System.out.println("I'm riding Bicycle");
}
}
class Tricycle extends Cycle{
public void ride() {
System.out.println("I'm riding Tricycle ");
}
}
class Unicycle extends Cycle {
public void ride() {
System.out.println("I'm Riding Unicycle ");
}
}
Jest to klasa TestRide
testować powyższy polimorfizm.
public class TestRide {
public static void ride(Cycle c){
c.ride();
}
public static void main(String[] args){
Cycle Cycling = new Cycle();
ride(Cycling);
Bicycle bi = new Bicycle();
ride(bi);
Tricycle tri = new Tricycle();
ride(tri);
Unicycle uni = new Unicycle();
ride(uni);
}
}
wyjście jest kod
I'm Riding generic Cycle()
I'm riding Bicycle
I'm riding Tricycle
I'm Riding Unicycle
Byte:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=5, args_size=1
0: new #17 // class com/polymorphism/Cycle
3: dup
4: invokespecial #24 // Method com/polymorphism/Cycle."
<init>":()V
7: astore_1
8: aload_1
9: invokestatic #25 // Method ride:(Lcom/polymorphism/
Cycle;)V
12: new #27 // class com/polymorphism/Bicycle
15: dup
16: invokespecial #29 // Method com/polymorphism/Bicycle
."<init>":()V
19: astore_2
20: aload_2
21: invokestatic #25 // Method ride:(Lcom/polymorphism/
Cycle;)V
24: new #30 // class com/polymorphism/Tricycle
27: dup
28: invokespecial #32 // Method com/polymorphism/Tricycl
e."<init>":()V
31: astore_3
32: aload_3
33: invokestatic #25 // Method ride:(Lcom/polymorphism/
Cycle;)V
36: new #33 // class com/polymorphism/Unicycle
39: dup
40: invokespecial #35 // Method com/polymorphism/Unicycl
e."<init>":()V
43: astore 4
45: aload 4
47: invokestatic #25 // Method ride:(Lcom/polymorphism/
Cycle;)V
50: return
Nawet w kodu bajtowego jej po prostu jako zwykłe wywołanie metody z invokestatic
i invokespecial
gdy myślałem, że użyłby invokedynamic
figury wersję metody odpowiednią dla faktycznego typu obiektu. Ale tak nie było.
W jaki sposób Java wykrywa rzeczywiste wywołanie metody podczas polimorfizmu, podczas gdy my po prostu przekazujemy obiekt upcasted w metodzie ride()
, takiej jak ride(bi)
w klasie TestRide
?
EDIT: RIDE metoda kodu bajtowego
public static void ride(com.polymorphism.Cycle);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokevirtual #16 // Method com/polymorphism/Cycle.r
ide:()V
4: return
Może twój przypadek testowy jest zbyt prosty. Jeśli kompilator Java wie w czasie kompilacji, jaka metoda zostanie wywołana, nie ma potrzeby, by kod bajtowy robił cokolwiek dynamicznie. – mastov
'invokedynamic' został wprowadzony w kodzie bajtowym JVM do dynamicznego wyszukiwania metod, które * nie * jest zgodne z wyszukiwaniem metody Java. Dlaczego używałby go kompilator Java? Wywołanie metody wirtualnej odbywa się za pomocą 'invokevirtual' i' invokeinterface'. Zauważ, że kompilator Java może oczywiście używać 'invokedynamic', jeśli chce. Specyfikacja języka Java nie mówi nic o tym, jak należy kompilować Javę, nie mówi nawet, że musi być skompilowana w ogóle, może równie dobrze zostać zinterpretowana. –
@ JörgWMittag Masz swój punkt :). Ale nadal pozostaje pytanie, jak to działa. –