Я как бы знаю принцип, что статическое связывание происходит во время компиляции, а динамическое связывание происходит во время выполнения. Я прочитал несколько связанных вопросов. Я мог бы проследить ход мыслей многих из них, но я снова запутался и потерял логику, когда ко мне пришел конкретный вопрос, как показано ниже:
class Cake {
public void taste (Cake c) {
System.out.println("In taste of Cake class");
}
}
class ChocolateCake extends Cake {
public void taste(Cake c) {
System.out.println("In taste (Cake version) of ChocolateCake class");
}
public void taste(ChocolateCake cc) {
System.out.println("In taste (ChocolateCake version) of ChocolateCake class");
}
}
class BirthdayCake extends ChocolateCake {
public void taste(Cake c) {
System.out.println("In taste (Cake version) of BirthdayCake class");
}
public void taste (ChocolateCake cc) {
System.out.println("In taste (ChocolateCake version) of BirthdayCake class");
}
public void taste(BirthdayCake bc) {
System.out.println("In taste (BirthdayCake version) of BirthdayCake class");
}
}
Были созданы следующие объекты:
Cake c1 = new Cake();
ChocolateCake cc = new ChocolateCake();
Cake c2 = new ChocolateCake();
Cake c3 = new BirthdayCake();
Вывод показан ниже:
c1.taste(cc);//Output: In taste of Cake class
cc.taste(cc);//Output: In taste (ChocolateCake version) of ChocolateCake class
c2.taste(cc);//Output: In taste (Cake version) of ChocolateCake class
((BirthdayCake) c3).taste(cc);//Output: In taste (ChocolateCake version) of BirthdayCake class
((BirthdayCake) c3).taste((BirthdayCake) c3);//Output: In taste (BirthdayCake version) of BirthdayCake class
По сути, мой вопрос: почему c2.taste(cc)
вызывает taste(Cake c)
метод в классе ChocolateCake
?
Вот моя мысль: статический тип c2
- это Cake
, который решает, что метод в Cake
будет вызываться. Когда дело доходит до времени выполнения, динамический тип c2, а именно ChocolateCake
, решает, будет ли вызываться метод в ChocolateCake
cake. И так как тип его параметра ChocolateCake
решил, что в конечном итоге будет вызван taste(ChocolateCake cc)
.
Видимо, эта мысль ошибочна. И если я предполагаю, что сигнатура метода была установлена во время компиляции, поскольку статический тип c2
равен Cake
, а в классе Cake
есть только один метод. Когда дело доходит до времени выполнения, он вызывает метод переопределения в классе ChocolateCake
. Все это имеет смысл. Меня смущает то, почему это работает так, а не по-прежнему?
Еще одна вещь, которую я не понимаю, заключается в том, что нам не разрешено писать оператор, подобный приведенному ниже, поскольку это приведет к ошибке компиляции:
ChocolateCake cc = new Cake();
.
Но почему ссылка на тип ChocolateCake может, наконец, передать объект Cake, поскольку он должен вызывать метод taste(Cake c)
в классе ChocolateCake
для получения правильного вывода, как указано выше.
Я думаю, что до сих пор не понимаю всего процесса вызова метода по ссылке на объект. Например, что происходит при выборе наиболее подходящего метода во время компиляции и что происходит после этого, скажем, во время выполнения (я не уверен, что в этом процессе есть какая-то другая фаза).
Может ли кто-нибудь помочь проиллюстрировать этот процесс? Большое спасибо!
Cake
во время выполнения, поскольку он был привязан кCake.cake(Cake c)
во время компиляции, но вызов метода (будучи динамическим) в конечном итоге будетChocolateCake.cake(Cake c)
. Вероятно, для этого вопроса есть хороший дубликат, давайте посмотрим, смогу ли я его найти. - person Kayaman   schedule 20.10.2017ChocolateCake
, наконец, передает объектCake
, в то время как оператор типаChocolateCake cc = new Cake();
даже не разрешен? - person Oscar Zhang   schedule 20.10.2017Cakes
, ноCake
неChocolateCake
(может быть, но это не точно). Вы бы не написалиWoman w = new Human();
, потому что это тоже не обязательно верно. - person Kayaman   schedule 20.10.2017