Запутанные привязки метода - PullRequest
2 голосов
/ 22 июля 2011

Результат этой простой программы: This is base.

public class mainApp{
    private void func(){
      System.out.println("This is base"); 
    }

    public static void main(String[] args){
        mainApp newObj = new derived();
        newObj.func();
    }
}

class derived extends mainApp{
    public void func(){ 
      System.out.println("This is derived"); 
    }
}
  • Мой вопрос: когда мы используем эту строку mainApp newObj = new derived();, на самом деле мы не создаем объект производный класс с использованием ссылки на базовый класс mainApp .Итак, когда я использую объект для вызова его метода, почему я не получаю метод из производного класса?Почему я получаю метод из базового класса.

  • , используя эту строку, mainApp newObj = new derived();, мы работаем со ссылкой mainApp ИЛИ мы работаем собъект производного класса .Какой из них правильный?

Ответы [ 2 ]

8 голосов
/ 22 июля 2011

Причина, по которой вы получаете метод базового класса, заключается в том, что версия базового класса func объявлена ​​private, а Java не позволяет частным методам переопределяться подклассами. Это означает, что если вы расширяете базовый класс и по чистой случайности решаете присвоить закрытой функции-члену то же имя, что и закрытой функции-члену в базовом классе, вы случайно не измените поведение функций-членов базового класса. Вы действительно работаете с объектом типа derived, но поскольку ссылка статически типизируется как mainApp, вызов func интерпретируется как вызов приватного метода func в mainApp а не публичный метод func в derived. Изменение кода для чтения

derived d = new derived();
d.func();

исправляет это, потому что статический тип d теперь derived, а вызов func имеет другое значение.

На уровне байт-кода JVM инструкция, используемая для вызова закрытых функций-членов, равна invokespecial, тогда как инструкция, используемая для вызова нормальных переопределяемых функций-членов, равна invokevirtual. У обоих совершенно разная семантика; invokespecial начинает поиск в текущем классе (или некотором базовом классе для таких вещей, как конструкторы), тогда как invokevirtual ищет в классе, соответствующем типу объекта во время выполнения.

0 голосов
/ 22 июля 2011

Вы работаете с классом derived. Ссылка на этот объект является mainApp. Это означает, что другие видят его как mainApp, но он реализован как производный класс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...