Во время выполнения каждый объект знает, каков его собственный класс, то есть класс, которым он был фактически создан.Его можно назначить переменной этого класса или любому суперклассу.При выполнении функции вы получаете «версию» этой функции для класса, в котором был создан объект, а НЕ для класса, в котором переменная, содержащая ссылку на объект, была объявлена как.пример вашего автомобиля / лексуса.Если вы напишите «Lexus mycar = new Lexus (); mycar.speedUp ();», то будет выполняться Lexus.speedUp, а не Car.speedUp.Может быть, это очевидно.Но даже если вы напишите «Автомобиль mycar = новый Lexus (); mycar.speedUp ();»выполняется все еще Lexus.speedUp, потому что это класс реального объекта.Вы можете переназначить объект различным переменным разных классов, как вам угодно, объект все еще знает свой «реальный» класс.
По сути, просто думайте о нем как о каждом объекте, имеющем скрытую переменную, которая содержит свой собственный тип класса., и это то, что он использует, чтобы найти функцию для выполнения.
Во время COMPILE компилятор не знает класс какого-либо данного объекта.Например, если вы напишите:
void speed1(Car somecar)
{
somecar.speedUp(1);
}
Компилятор не знает, является ли автомобиль здесь Lexus или Honda, или что.Он просто знает, что это машина, потому что не знает, где и как будет вызываться эта функция.Фактический тип машины не будет известен до времени выполнения.
Следствием этого является то, что если вы попытаетесь написать:
void speed1(Object somecar)
{
somecar.speedUp(1);
}
Компилятор выдаст ошибку на этом,У него нет возможности узнать, что Object - это Автомобиль, поэтому он не знает, что speedUp - допустимая функция.
Даже если вы написали:
Object mycar=new Lexus();
mycar.speedUp(1);
Вы получите ошибку.Как человек, читающий код, вы можете легко увидеть, что mycar должен быть Lexus и, следовательно, Car, но компилятор просто видит, что mycar объявлен как Object, а Object не имеет функции speedUp.(Полагаю, достаточно умный компилятор мог бы понять в этом тривиальном примере, что mycar должен быть Lexus, но компилятор не может работать с тем, что он может знать иногда или большую часть времени, он должен иметь дело с абсолютами.)
Редактировать: Ответ на вопрос в комментарии.
RE вопрос 3: Я понимаю, где вы здесь запутались.Вы должны отличать СКОРОСТЬ ВРЕМЕНИ от РАБОТЫ.
Когда вы выполняете функцию над объектом, вы получаете «версию» этой функции, специфичную для «реального» класса этого объекта.Например, если вы напишите:
Car car1=new Lexus();
Car car2=new Chrysler(); // assuming you defined this, of course
car1.speedUp(1); // executes Lexus.speedUp
car2.speedUp(2); // executes Chrysler.speedUp
Но это БЕЗОПАСНО.Во время COMPILE все, что знает компилятор, это тип переменной, содержащей ссылку.Это может быть то же самое, что и «реальный» класс объекта, или это может быть любой суперкласс вплоть до Object.В обоих случаях это Автомобиль.Так как Car определяет функцию speedUp, вызов car1.speedUp является законным.Но вот что важно: во время компиляции Java знает, что у Car есть функция speedUp, поэтому вызов speedUp для объекта Car является законным.Но он не знает и не заботится о том, какую функцию ускорения вы получите.То есть, когда вы говорите car2.speedUp, Java знает, что car2 - это Car, потому что это объявленный тип.Он не знает - помните, что мы говорим во время компиляции, а не во время выполнения - он не знает, является ли это Lexus или Chyrsler, просто что это автомобиль.Только во время выполнения он узнает, какой это тип машины.