#java #ооп #полиморфизм
Изучая наследование и полиморфизм в java наткнулся на такой пример: class A { int a = 5; String doA() { return“ a1“; } protected static String doA2() { return“ a2“; } } class B extends A { int a = 7; String doA() { return“ b1“; } public static String doA2() { return“ b2“; } void go() { A myA = new B(); System.out.print(myA.doA() + myA.doA2() + myA.a); } public static void main(String[] args) { new B().go(); } } Результат выполнения программы: "b1 a2 5" b1 - тут понятно. фактический тип класса является B, через динамическое связывание компилятор вызывает метод doA(), определенный в классе B. a2 - метод doA2() определен статическим, соответственно происходит ранее связывание, компилятор вызывает метод класса A, а не экземпляра 5 - вот тут-то для меня и происходит магия. почему не 7? переменная не static и не final? фактический тип класса B
Ответы
Ответ 1
A myA = new B(); ^ Потому что поля в Java не являются полиморфными, соответственно используется класс указателя, в данном случае это класс A. По поводу методов: в Java все методы являются виртуальными, соответственно используется динамическое (или, как его еще называют, позднее) связывание. Поэтому на этапе выполнения JVM определяет тип объекта B, на который ссылается указатель myA и вызывает соответствующую реализацию метода doA() класса B.Ответ 2
Если вкратце, то всё дело в том, что у вас одинаковые имена переменных и вы фактически имеете две переменные с именем a и происходит Variable shadowing, т.е. когда одна переменная перекрывает другую. В вашем же случае происходит еще и случай описанный в документации: If an expression name consists of a single Identifier, then there must be exactly one visible declaration denoting either a local variable, parameter or field in scope at the point at which the the Identifier occurs. Otherwise, a compile-time error occurs. If the declaration declares a final field, the meaning of the name is the value of that field. Otherwise, the meaning of the expression name is the variable declared by the declaration. Т.е. переменная ищется в скопе класса A, даже если это фактически является классом B. Если же вы хотите, чтобы менялось значение переменной для класса B. То надо сделать, например, так: class B extends A { //int a = 7; B() { a = 7; } // весь остальной код }Ответ 3
Тип класса B, но в данном случае он скастован к классу A, а поскольку и в A и в B поле a приватное (по умолчанию, без модификатора, оно приватное), то мы обращаемся к переменной a именно класса A, где оно равно 5
Комментариев нет:
Отправить комментарий