Почему sysout (верхний класс) вызывает toString нижнего класса после присвоения нижнего класса верхнему классу? - PullRequest
0 голосов
/ 07 сентября 2011

У меня есть два класса A и B, в то время как B является подтипом A:

public class A {
    private String stringVar;

    public A()  {
        stringVar = "";
    }

    public String getStringVar() {
        return stringVar;
    }

    public void setStringVar(String str) {
        this.stringVar = str;
    }

    @Override 
    public String toString()  {
        return getStringVar();
    }
}

Класс B:

public class B extends A {
    private int intVar;

    public B()  {
        intVar = 0;
    }

    public int getIntVar() {
        return intVar;
    }

    public void setIntVar(int intVar) {
        this.intVar = intVar;
    }

    @Override
    public String toString()  {
        return super.toString() + " " + getIntVar();
    }
}

Как вы можете видеть в следующем основном методе, я назначаю b для a. Теперь «a» не может вызывать методы b, что понятно, потому что сейчас я использую экземпляр типа A. Но он ведет себя как B, когда вызывается toString. Любопытно, я бы ожидал строки. Почему это так?

public class Main {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        b.setIntVar(200);
        b.setStringVar("foo");
        a = b;
        System.out.println(a);
    }
}

Ответы [ 7 ]

2 голосов
/ 07 сентября 2011

Потому что указывает на реализацию Б. И объявлен как А.

Итак, поведение Б. И методы, видимые из А.

Чтобы использовать методы B, сделайте вот так

((B) a).getIntVar();

Думай об этом так

Object o = new FancyObject();

При компиляции этого метода будут приниматься только методы Objects, хотя это FancyObjcet с большим количеством методов.

Чтобы использовать методы FancyObject для o, выполните следующие действия.

Object o = new FancyObject();
(FancyObject o).fancyMethod();

Цитата "потому что я сейчас использую экземпляр типа A" Вы все еще используете экземпляр типа B. Вы можете видеть его так, как будто вы повысили b, но это тот же экземпляр.

Перекрестная ссылка с другого сайта с кредитами на картинке. Если это противоречит правилам, кто-то может редактировать эту часть моего ответа. enter image description here

1 голос
/ 07 сентября 2011

Понятие, которое вам нужно понять, это разница между ссылками и объектами.

a - это ссылка (в данном случае локальная переменная), которая указывает сначала на объект типа A, а затем на объект типа B.

Компилятор знает, что он должен иметь тип A (или его подтип), поэтому он может безопасно вызывать все методы, определенные A, но они будут вызываться для фактического объекта, а не для исходного типа a.

1 голос
/ 07 сентября 2011

Это природа методов наследования / полиморфизма и переопределения.

Переопределенные методы будут определены во время выполнения на основе реального типа объектов, а не на основе ссылочного типа.

Следовательно, a.toString () на самом деле b.toString (), потому что он определяется во время выполнения.

http://download.oracle.com/javase/tutorial/java/IandI/override.html

0 голосов
/ 07 сентября 2011

Нет, B Переопределяет метод toString для A, поэтому, если объект является экземпляром B, когда вы вызываете его метод toString, вы получаете любой метод, который имеет этот экземпляр. В общем случае, если у вас есть объект и вы вызываете его методы, вызывается метод, который находится в экземпляре, а не в типе переменной. Единственное исключение - статические методы.

В C ++ это не так. Вызывается метод с типом переменной, если таковой существует, если только вы явно не выберете описанное выше поведение, сделав метод виртуальным.

0 голосов
/ 07 сентября 2011

Именно так работает полиморфизм Java во время выполнения.Все, что имеет значение, это фактический тип во время выполнения.Что вы сделали, так это взяли ссылку на A и указали на экземпляр из B.Вы изменили тип вещи, на которую указывает a.

Попробуйте

a = (A)b;

0 голосов
/ 07 сентября 2011

Это полиморфизм: объект, который содержит объект, имеет статический тип A, но все еще является объектом динамического типа B. Поэтому динамическая диспетчеризация выбирает переопределенную функцию toString (), определенную в B.

0 голосов
/ 07 сентября 2011
...