Dwie ważne rzeczy do wywołania metod.
Masz dwa razy: czas kompilacji i czas wykonywania.
Zasady nie są takie same między tymi dwoma razy.
w czasie kompilacji kompilator musi określić statycznie, jaki dokładny podpis metody jest nazywany, aby skompilować dobrze.
To powiązanie jest statyczne, ponieważ kompilator nie ma wpływu na konkretną instancję, w której wywoływana jest metoda i to samo dotyczy parametrów przekazywanych do metody.
Kompilator nie polega na typach efektywnych, ponieważ w środowisku wykonawczym typy efektywne mogą ulec zmianie w trakcie wykonywania.
Tak więc kompilator przeszukuje dostępne metody dla zadeklarowanego typu, który jest bardziej szczegółową metodą zgodną z zadeklarowanymi typami parametrów przekazanych do tego typu.
w środowisku wykonawczym metoda instancji z klasy lub z innej będzie używana zgodnie z efektywną instancją, w której wywołana jest metoda.
Jednak metoda wywoływana musi być zgodna z sygnaturą określoną podczas kompilacji.
1) W pierwszym przypadku:
Fox foxi = new Fox();
Dog hybrid = new Fox();
System.out.println(hybrid.play(foxi)); // Output number 1
Na przykład kotów, kompilator musi znaleźć najbardziej odpowiednią metodę play()
jako parametr zmienna z zadeklarowanym typem Fox.
W klasie Dog, pojedyncza metoda play()
z podpisem zgodnym istnieje:
public String play(Dog d) {
Więc podpis ten jest używany do wiązania: String play(Dog d)
.
O metodzie bark()
jest to o wiele bardziej oczywiste, ponieważ istnieje tylko jeden podpis metody bark().
Więc nie mamy niejednoznaczność w sprawie sposobu, który jest związany w czasie kompilacji
- Drugi raz (wykonawczego):
przy starcie metoda betonowej przykład String play(Dog d)
jest wywoływany. Zmienna hybrid
odnosi się do instancji Foxa, ale Fox nie zastępuje String play(Dog d)
. Fox definiuje metodę play(), ale z innym podpisem:
public String play(Fox f) {
Więc JVM wywołuje metodę psa public String play(Dog d) {
.
Następnie wywołuje metodę efektywnego typu d
po wykonaniu d.bark()
, a d
odnosi się do instancji .
Wypisuje "WuffRingding".
2) W drugim przypadku:
Fox foxi = new Fox();
Dog hybrid = new Fox();
System.out.println(foxi.play(hybrid)); // Output number 2
- pierwszy raz (kompilacji)
Na przykład Fox
kompilator musi znaleźć najbardziej odpowiednią metodę play()
jako parametr zmienna o zadeklarowanym typie Dog
.
W Fox
klasie, dwie play()
metody z parametrem zgodnym istnieje:
public String play(Dog d) { // inherited from the parent class
public String play(Fox f) { // declared in Fox
Kompilator musi wybrać bardziej konkretny sposób kontekście wywołania metody
identyfikuje sposób bardziej szczegółowy, że drugi dla zadeklarowanego parametru typu: public String play(Dog d)
. Kompilator wiąże wywołanie metody play()
z public String play(Dog d)
podczas kompilowania klasy.
W czasie wykonywania metoda konkretnej instancji String play(Dog d)
jest wywoływany.
Jeśli chodzi o pierwszy przypadek, zmienna foxi
odnosi się do instancji Fox, ale Fox nie zastępuje String play(Dog d)
.
Tak więc JVM wywołuje metodę Dog od public String play(Dog d)
.
Następnie wywołuje metodę efektywnego typu f
, gdy wykonywana jest f.bark()
, a f
odnosi się do instancji Fox
.
"WuffRingding" ponownie wyświetla się.
Aby uniknąć tego rodzaju zaskoczenia należy dodać @Override
w metodach mających zastąpić metody klasy dominującej:
na przykład:
@Override
public String play(Fox f) {
return "Ringding" + f.bark();
}
Jeśli metoda nie skutecznie zastępują play(Fox f)
metoda w hierarchii, kompilator narzeka na to.
Istotne jest to, że 'Fox.play (Fox)' nie zastępuje 'Dog.play (Dog)'. Ponieważ typ 'hybrid' to' Dog', wywoływane jest przeciążenie 'play (Dog)'. –
@AndyTurner cześć Andy, dziękuję za odpowiedź. Nadal, jeśli chodzi o typowanie, typ siłowy ma znaczenie? Powiedzmy, że rzuciłem (Dog) na instancję Foxa i zadzwonię do metody kory, nadal będzie to metoda w klasie Fox, prawda? Jestem trochę zdezorientowany między odniesieniem a rzutowaniem .. –
Metoda do wywołania jest określana w czasie kompilacji, a nie w czasie wykonywania. Tak więc, jeśli podasz odniesienie do "psa" do metody, wywoływane jest przeciążenie polegające na wywołaniu "psa" - nawet jeśli odnosi się to do 'Foxa' w czasie wykonywania. –