Этим и полезно знание знакомство с C++ (=
Суть в чем: куда-то в память загружается объект-тип (не экземпляр с данными, а именно представление типа), в котором физически располагается код методов. У каждого экземпляра классов есть ссылка на свой объект-тип. Когда тип ссылки на объект совпадает с его типом, то все просто: мы знаем, что метод можно найти напрямую. Открываются перспективы для оптимизации компилятора: подстановка конкретного адреса метода или даже инлайнинг (когда вызов метода заменяется непосредственно на код из метода, чтобы не тратить такты на передачу параметров). Это раннее связывание.
Если же у нас возможен полиморфный вызов (переменная-ссылка может указывать на объект-наследник, у которого может быть переопределение родительского метода), то нужно узнать точно какого типа объект, чтобы вызвать подходящее определение метода из нужного типа. Увы, это мы узнаем только в рантайме, поэтому компилятор не поможет оптимизировать этот процесс. Это позднее связывание.
Во многих Си-подобных языках (C++, C# и т.п.) в угоду производительности используется раннее связывание по умолчанию: полиморфные методы должны явно помечаться программистом ключевым словом virtual
(иначе будет вызываться метод из типа переменной-ссылки, не полиморфно), в Java же в угоду читаемости кода используется позднее связывание по умолчанию: все методы неявно "virtual", так что качество связывания отдается на откуп компилятору.
Конечно, есть возможность пометить метод ключевым словом final
, что запретит переопределять метод в наследниках, т.е. у компилятора появятся все полномочия жестко вбить необходимый адрес метода в точку вызова без страха, ибо альтернативных версий метода в наследниках просто быть не может.
(В С++11 также есть ключевое слово final
, а в C# - sealed
)