Постоянным читателям хорошо известно, что я недолюбливаю java. Как только я начал чуть забывать, почему, она решила мне преподнести очередной сюрприз. Возьмем простенький класс

public class TestClass {
  public void foo(){ System.out.println(getBar()); }

  String getBar(){ return "bar"; }
}

И создадим от него наследника, переопределяя метод (довольно частый прием в тестах):

new TestClass(){
  String getBar() { return "baz"; }
}.foo();

Как думаете, что выведет foo?

Ответ

Правильный ответ — неизвестно. Потому что если вызывающий класс находится в том же пакете, то baz, а если в другом — то bar. И компилятор даже предупреждения не даст. Т.е. простой перенос класса из одного пакета в другой ломает функциональность без предупреждений.

Казалось бы — используй @Override и будет счастье: если попытаешься переопределить то, чего нет, то получишь ошибку. Но возникает вопрос: а какого черта тогда компилятор спокойно делает переопределение без этой аннотации?