Короче говоря, вы перегружаете предполагаемое значение «переопределения» в Java :-).
Давайте сделаем вид, что кто-то написал класс Animal
: (переписывая его немного, не меняя семантики, но демонстрируя хорошую практику). Мы также будем считать, что Animal
компилирует и работает нормально:
public class Animal {
public static void main(String args[]) {
Animal a = new Animal(); // yes, Animal, no Horse yet.
a.eat();
}
///// Animal's private methods, you should not look here
private void eat() {
System.out.println("animal eating");
}
///// Animal's private methods, you should not look here
}
Это хороший Java кодирования практике, так как автор Animal
класса не хочет, чтобы вы, читатель этого кода, чтобы действительно знать ничего о Animal
" частный бизнес.
Далее вы посмотрите на метод public static void main
Animal
и правильно сделаете вывод, что существует определенный здесь метод eat()
. На данный момент, имеет место следующее:
- Как и любой другой класс в Java,
Animal
расширяет Object
.
- Вы смотрите на общедоступные (и защищенные) методы
Object
и обнаружите, что нет такого метода, как eat()
. Учитывая, что Animal
компилирует штраф, вы можете заключить, что eat
ing должен быть Animal
's частный бизнес! Нет другого способа, который мог бы скомпилировать Animal
. Таким образом, не глядя на частный бизнес Animal
, вы могли бы заключить, что существует eat()
метод в Animal
класс частный!
Теперь давайте предположим, что ваша цель в том, чтобы создать другое животное под названием Horse
в качестве специализированного Animal
и придать ему особое поведение еды. Вы видите, что вы находитесь , а не, чтобы посмотреть в Java Lang Spec и узнать все правила этого и просто использовать ключевое слово extends
и покончить с ним. Затем появляется первая версия Horse
. Вы где-то слышали, однако, что это лучше уточнить ваше намерение перекрывая (это одна вещь, которую вы сейчас уверены - вы хотите переназначенияeat
ИНГ поведение Horse
):
class Horse extends Animal {
@Override
public void eat() {
System.out.println("Horse eating");
}
}
Right ; вы добавляете тег @Override
. Это всегда хорошая идея, по общему признанию, при увеличенной формулировке (это хорошая практика по нескольким причинам, в которые мы не будем входить здесь).
Вы пытаетесь скомпилировать Horse.java
, и вы увидите:
Error:(21, 5) java: method does not override or implement a
method from a supertype
Таким образом, компилятор, который знает язык программирования Java лучше, чем у нас, говорят нам, что мы, на самом деле, не наиважнейших или реализующими метод, который объявлен в супертипом.
Теперь обработка переопределения на Java становится понятной для нас.Поскольку мы должны только переопределять это поведение, предназначенное для переопределения, а именно публичные и защищенные методы, мы должны быть осторожны в том, как написаны суперклассы. В этом случае, непреднамеренно, суперкласс Animal
, который, по-видимому, был разработан для расширения, не позволял подклассам переопределять поведение eat
!
Даже если мы удалили тег @Override
, чтобы избавиться от технической ошибки или предупреждения компилятора, мы не обязательно будем поступать правильно, потому что во время выполнения, как вы заметили, непреднамеренный метод, чья подпись соответствует, получает называется. Это еще хуже.
Ну, не вы объяснить это чуть выше. Объявленный тип '' 'Animal, а не Horse, и Animal.eat() является закрытым, поэтому его нельзя переопределить, поэтому его нельзя назвать полиморфно. Метод подкласса будет вызываться, если он переопределяет класс базового метода, но он этого не делает, поэтому ... –
@ JBNizet, да, но они почему метод еды класса животных называют, что я не могу понять. Это потому, что у нас есть ссылка типа класса Animal? Но у нас есть объект типа Horse. то почему он вызывает метод класса Animal? –
Весь компилятор знает о 'a' о том, что это Animal: это его объявленный тип. Таким образом, компилятор ищет метод eat() в Animal. Он находит один, и он частный, поэтому он называет этот метод. И поскольку его нельзя переопределить, вызывается Animal.eat(). –