2013-05-21 2 views
1

В такой ситуации:полиморфизм и наследование

class A{ 
    public int x = 4; 
    public void s3(){ 
     x = 3; 
    } 
    public void f(){ 
     x = 8; 
     s3(); 
    } 
} 

class B extends A{ 
    public int x = 5; 
    public void f(){ 
     x = 10; 
     s3(); 
    } 
} 

A a = new B(); 
B b = (B) a; 
a.f(); 
System.out.println(b.x); 
System.out.println(a.x); 

a.f() называет f() класса B, затем f(), после присваивания, вызывает функцию s3(). На этом этапе s3() определяется только в A и когда он присваивает значение 3 x, x является копией переменной, принадлежащей классу A. Почему s3() не использует x, объявленный в B? Теоретически, B не должен иметь свою собственную копию функции s3(), унаследованной от A? (Так s3() унаследовал от A в B должны использовать x объявленный в B)

+3

Для дальнейшего использования использование отдельных символов в качестве имен для всех ваших переменных, методов и имен классов делает ваш код трудным для подражания. –

+0

«Почему' s3() 'не использует' x', объявленный в 'B'?" Для этого 'B' должен переопределить' s3() ', который отличается от наследования. –

ответ

5

У вас есть непонимание того, что вы должны делать в наследстве. extends - это зарезервированное слово, которое было выбрано мудро. Точка B, простирающаяся на A, состоит в том, чтобы сказать, что B является подмножеством A с дополнительными атрибутами. Вы не должны переопределять x в B; A должно обрабатываться x. Переопределяя x в подклассе, вы скрываете поле суперкласса x (это верно, даже если x относится к различным типам переменных).

A a = new B(); 
System.out.println(a.x); //4 makes sense, since we are of class A 
B b = (B) a; 
System.out.println(b.x); //5 makes sense, since we are of class B 
a.f(); 
System.out.println(a.x); //3 makes sense, since a.f() calls s3(), which sets A's x to 3 
System.out.println(b.x); //10 

10-следует из печати X B, которая назначена на 10 с вызовом a.f(), который затем вызывает s3() именно поэтому 3-й пример печатает 3. Для того, чтобы увидеть, что я имею в виду смотреть на это:

public void f() 
    { 
     x = 10; //sets B's x to 10 
     s3(); //calls A's s3(), which sets A's x to 3. 
    } 
+0

, если он не может переопределить x в B, то что такое переменная затенение .. насколько я знаю .... public class Base { public String name = "Base"; public String getName() {return name; } } открытый класс Sub extends Base { public String name = "Sub"; public String getName() {return name; } } это переменная тень – argentum47

+0

Я отредактировал свой ответ, чтобы включить объяснение относительно того, что происходит. –

+0

Я видел его, как только вы его отредактировали :) – argentum47

0

Потому что это то же самое. У вас нет двух экземпляров («экземпляров») объекта, только один.

С тех пор, как вы создаете экземпляр B (new B()), он будет использоваться способами, указанными в B. Конечно, когда в B не определены методы, он будет использовать реализацию методов суперкласса.

Итак, у вас есть только атрибут x, а s3 заставляет его 3. Он работает нормально.

0

Почему s3() не использует x, объявленный в B?

Как правило, методы родительского класса не могут видеть переменные-члены в дочернем классе.

Я думаю, что делает именно это:

B b = new B(); 
b.f(); 

достаточно, чтобы воспроизвести по крайней мере часть вашего замешательства. Вот что е() выглядит в B:

class B extends A{ 
    public int x = 5; 
    public void f(){ 
     x = 10; 
     s3(); 
    } 
} 

е() эквивалентно:

public void f(){ 
     this.x = 10; 
     this.s3(); 
    } 

Так вызывающему б.F() означает, что F() эквивалентно:

public void f(){ 
     b.x = 10; 
     b.s3(); 
    } 

Далее, что происходит внутри метода s3() в? s3() выглядит следующим образом:

public void s3(){ 
     x = 3; 
    } 

и что эквивалентно:

public void s3(){ 
     this.x = 3; 
    } 

«это» это объект, который вызвал метод, который из последнего примера F() вы можете увидеть это б. Так s3() эквивалентно:

public void s3(){ 
     b.x = 3; 
    } 

Так b.x получает перезаписаны с 3 ... uhhhhm не так быстро!

Экземпляр B также наследует й из А, это просто, что внутри Б бывает так, что Б х тень х от А. В результате, метод F() в B назначает й из B. Внутри s3(), однако, x, который получил от A, больше не затеняется, и что касается A, то существует только один x - тот, который принадлежит A. Другими словами, поиск bx принимает другое путь в зависимости от того, какой класс этот оператор появляется.

После выполнения s3() конечный результат состоит в том, что b имеет два x с двумя разными значениями. Внутренние методы в B, x из B будут видны, а внутри методов в A будет отображаться x из A. Внутри методов в B можно получить от x от A, используя super.

Теоретически, B не должен иметь свою собственную копию функции s3(), унаследованной от A?

Не думайте о копиях. Подумайте с точки зрения указателей от класса к классу и указателей от классов до поисковых таблиц. Обычно в компьютерном программировании каждый экземпляр имеет свои собственные переменные экземпляра, но методы разделяются всеми экземплярами класса.

Смежные вопросы