2013-09-05 3 views
0

Я знаю, что в случае переопределения методов Java следует динамическому связыванию. Но если мы вызываем только дочерний метод из родительской ссылочной переменной, относящейся к дочернему объекту, мы получили ошибку компиляции.
Почему java следует этому дизайну (то есть почему нет динамического связывания во втором случае)?Почему различный дизайн для динамического привязки и вызова метода child only из родительского класса?

class A{ 
    public void sayHi(){ "Hi from A"; } 
} 


class B extends A{ 
    public void sayHi(){ "Hi from B"; 
    public void sayGoodBye(){ "Bye from B"; } 
} 


main(){ 
    A a = new B(); 

    //Works because the sayHi() method is declared in A and overridden in B. In this case 
    //the B version will execute, but it can be called even if the variable is declared to 
    //be type 'A' because sayHi() is part of type A's API and all subTypes will have 
    //that method 
    a.sayHi(); 

    //Compile error because 'a' is declared to be of type 'A' which doesn't have the 
    //sayGoodBye method as part of its API 
    a.sayGoodBye(); 

    // Works as long as the object pointed to by the a variable is an instanceof B. This is 
    // because the cast explicitly tells the compiler it is a 'B' instance 
    ((B)a).sayGoodBye(); 

} 

ответ

1

Перед динамической отправкой вызова метода может прийти в действие, то код должен пройти через компилятор. Когда вы вызываете метод с использованием ссылки класса C, компилятор ищет объявление этого метода в этом классе C. Компилятор только беспокоится о том, какой тип ссылки он имеет. Он может только проверять вызов метода на эту большую информацию. Если он не может найти метод в классе C, он даст вам ошибку компилятора.

Таким образом, для вызова:

a.sayGoodBye(); 

Поскольку a является ссылкой класса A, компилятор будет искать метод в классе A, и если он не может найти, это даст ошибку компилятора.

+0

Но во время выполнения следует динамическое связывание. Значения Я могу сказать, что для вызова 'a.sayHi()' compile попытайтесь найти 'sayHi()' объявление 'sayHi()' в A и, поскольку он существует там, поэтому нет ошибки. Затем во время выполнения вещи вызывается на основе объекта (т. Е. Адреса памяти), и там лежит определение C 'sayHi()', поэтому оно вызывается. И для метода 'sayGoodbye', когда вы получаете ошибку во время компиляции (как вы объяснили), не должно быть и речи о том, какое определение вызывается во время выполнения. –

+0

@knoxxs. Да, точно. Во время выполнения не возникает вопросов о поведении, когда код даже не компилируется. –

0

Bis aA, но Ais not necessarilyB. Таким образом, метод B не может быть вызван на A ссылка

+0

, но в случае переопределения метода это происходит. –

0

Думайте так: когда B расширяет A; это означает

B = <All non-private stuff of A> + Its own stuff 

Это означает, что B имеет все привилегии использовать материал из A. (его, как становится подмножеством B)

But A никогда не знал о Б здесь и то, что B содержит; поэтому он не может использовать материал B. Если каким-то образом нужно заставить A вести себя как B (мы используем cast), и так как здесь A is not B; кастинг будет неработоспособным во время выполнения.

Чтобы узнать больше о кастинге Java, пожалуйста, прочитайте This thread

+0

Но тогда почему в случае переопределения A может обратиться к определению метода B? –

+0

Я не получил «переопределения»? Не могли бы вы добавить пример переопределения A и доступа к методу B? Если вы говорите о неудаче второго случая в своем примере, это потому, что во время компиляции ссылка имеет тип A; поэтому видны только методы A. Если вы знали, что A действительно содержит ссылку на B, вам нужно сообщить компилятору, используя Casting. Поскольку B является дочерним элементом A, любая ссылка на B не требует кастинга, потому что компилятор точно знает, что B является A (и, следовательно, он может вести себя как A). – gyan

+0

Посмотрите, что печатается при вызове 'a.sayHi()'. –