Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Переопределение методов


Автор: Thor_75t 30.9.2009, 19:33
Извиняюсь за возможно неверное расположение материала, но меня мучает незнание ответа, а тут насколько вижу рассматриваются как раз задачки и даются ответы. Надеюсь что мне подскажут smile
Ситуация следующая- имею такой код:
Код

class Bz{
    Bz(){System.out.print("Bz.constr()");}
    public Bz getB(B bbb) {
        System.out.println("Bz");        return null;}
}
class Bt extends Bz{
    Bt(){System.out.print("Bt.constr()");}
    public Bt getB(Bz bbb){
        System.out.println("Bt");        return null; }
}
class B extends Bt{
    B(){System.out.print("B.constr()");}
    public B getB(Bt bbb){
        System.out.println("B");        return null;  }
}
class B1 extends B {
    B1(){System.out.print("B1.constr()");}
    public B1 getB(Bt bbb){
        System.out.println("B1");        return null;    }
}
class A {
    protected Bt b=new B();
    public void getBfromA(){
        b.getB(null);    }    
}
public class Start extends A {
    
    public Start(){
        b = new B1();
    }
    
    public static void main(String[] s){
        A a = new Start();
        a.getBfromA();
    }
}

Результат работы на консоли-
Bz.constr()Bt.constr()B.constr()Bz.constr()Bt.constr()B.constr()B1.constr() Bz
Почему срабатывает метод getB объекта Bz?? В ссылочной переменной b экземпляра a хранится ссылка на B1.
Следовательно должен вызываться метод, ассоциированный с типом хранящегося экземпляра B1, т.е. вызывается переопределённый метод getB внутри объекта B1(родной вызов getB в BZ отбрасываем, т.к. он содержит ссылочный параметр Bz). Не могу понять что я не понимаю smile подскажите в какую сторону думать.
С уважением Тор.
С нетерпением буду ждать ответа (пусть даже и с подковыркой, быть может для профи мой лёгкий вопрос будет смешным smile

Автор: revenforv 30.9.2009, 21:13
А мысль в том, что методы, которые вы считаете виртуальными - таковыми не являются:

1: getB(B bbb) в Bz
2: getB(Bz bbb) в Bt
3: getB(Bt bbb) в B
4: getB(Bt bbb) в B1

Виртуальный здесь только метод 3 и его переопределенная версия 4.

Согласно спецификации языка, поиск нужного метода осуществляется так. Вначале определяется стартовая точка поиска. Поскольку вызов типа virtual - поиск начинается с класса B1 (runtime type)
В поиске участвует класс Bz - это compile time type

В начале проверяется, есть ли совместимый с get(null) метод в B1 (он есть), далее т.к. вызов виртуальный, то проверяется - переопределяет ли этот метод метод Bz.getB(B bbb) (не переопределяет, т.к. сигнатуры не совпадают). Поскольку в B1 метод не найден - поиск продолжается в его суперклассе, т.е. в B. Затем по той же причине в Bt и, наконец, в Bz.

Для того чтобы таких досадных ошибок и непоняток не возникало в JDK1.5 была введена аннотация @Override, если бы вы воспользовались ею при написании метода getB(), то ошибка компиляции возникла бы уже в классе Bt

Автор: Thor_75t 30.9.2009, 21:31
Спасибо revenforv  smile  
Сейчас прогоню на компиляторе, чтоб освоить, укрепить и перестать наконец путаться в основах smile  как я раньше страдал.
Насчёт @Override - интересно, но, думаю- что лучше полагаться на себя, чем на помощь дружественных методов smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)